Разработка и Конфигурация · 12 мин
1С: как передать форму на сервер
Как в 1С передать данные формы на сервер: директивы &НаСервере и &НаСервереБезКонтекста, передача параметров, типичные ошибки и ограничения платформы.
В управляемом приложении 1С форма выполняется на клиенте, а работа с базой данных, запросами и объектами возможна только на сервере. Поэтому типовая задача разработчика — передать данные формы на сервер, выполнить там обработку и вернуть результат обратно. Делается это через серверные процедуры и функции в модуле формы с директивами компиляции &НаСервере и &НаСервереБезКонтекста.
Ключевой момент, который нужно понять сразу: саму форму как объект «передать на сервер» нельзя. На сервер уходят только сериализуемые данные — реквизиты формы, параметры и значения примитивных типов, ссылки, структуры, таблицы значений. Контекст формы (элементы, оформление, свойства окна) существует только на клиенте.
Ниже разобраны оба способа серверных вызовов, различия между ними, ограничения платформы, типичные ошибки и способы проверить, что передача данных работает корректно.
Как устроен вызов сервера из формы
В модуле управляемой формы каждая процедура и функция помечается директивой компиляции: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста или &НаКлиентеНаСервереБезКонтекста. Директива определяет, где будет исполняться код. Когда клиентская процедура вызывает серверную, платформа сериализует переданные параметры, отправляет их на сервер, выполняет код и возвращает результат.
Каждый такой вызов — это сетевое обращение (в клиент-серверном варианте) или как минимум переключение контекста (в файловом). Поэтому серверные вызовы в цикле или при каждом нажатии клавиши — частая причина «тормозов» интерфейса. Правильный подход — собрать данные на клиенте и передать их одним вызовом.
Передача формы через &НаСервере
Процедура с директивой &НаСервере выполняется на сервере, но имеет доступ к контексту формы: реквизитам, их значениям, объекту формы через РеквизитФормыВЗначение() и ЭтаФорма. Фактически платформа сама передаёт состояние реквизитов формы на сервер и после выполнения синхронизирует изменения обратно.
Типовой пример — обработка данных объекта, скажем пересчёт табличной части документа:
&НаКлиенте
Процедура Пересчитать(Команда)
ПересчитатьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПересчитатьНаСервере()
Объект.Сумма = 0;
Для Каждого Строка Из Объект.Товары Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
Объект.Сумма = Объект.Сумма + Строка.Сумма;
КонецЦикла;
КонецПроцедуры
Здесь данные формы (реквизит Объект) автоматически доступны на сервере. Это удобно, но есть цена: платформа передаёт весь контекст формы туда и обратно, что на «тяжёлых» формах с десятками реквизитов и большими таблицами даёт заметные накладные расходы.
Передача данных через &НаСервереБезКонтекста
Директива &НаСервереБезКонтекста означает, что процедура не имеет доступа к реквизитам формы. Все нужные данные передаются явно через параметры, а результат возвращается через Возврат или параметры, переданные по ссылке (в 1С значения параметров изменяются, если они не объявлены с Знач).
&НаКлиенте
Процедура РассчитатьЦену(Команда)
НоваяЦена = РассчитатьЦенуНаСервере(Объект.Номенклатура, Объект.Количество);
Объект.Цена = НоваяЦена;
КонецПроцедуры
&НаСервереБезКонтекста
Функция РассчитатьЦенуНаСервере(Номенклатура, Количество)
Запрос = Новый Запрос("ВЫБРАТЬ Цена ИЗ РегистрСведений.Цены
|ГДЕ Номенклатура = &Номенклатура");
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Цена * Количество;
КонецЕсли;
Возврат 0;
КонецФункции
Этот вариант считается предпочтительным: передаются только нужные данные, код легче тестировать, а зависимость от контекста формы отсутствует. На практике в типовых конфигурациях большинство серверных вызовов из форм сделано именно «без контекста».
Сравнение вариантов
Подходит, когда нужно работать с реквизитами формы или объектом целиком. Ограничение: передаётся весь контекст формы, медленнее на тяжёлых формах.
Подходит для точечных операций: запросы, расчёты, проверки. Передаются только параметры — быстрее и чище, но данные формы нужно передавать и возвращать явно.
Подходит для переиспользуемой логики: вызов из формы процедуры общего модуля с флагом «Сервер». Форма вообще не участвует, передаются только параметры.
Какие данные можно передать на сервер
На сервер из клиентской процедуры формы можно передать: примитивные типы (число, строка, дата, булево), ссылки на объекты базы данных, структуры и соответствия, массивы, таблицы значений (через реквизит формы или преобразование), а также ДанныеФормыСтруктура, если вызов идёт внутри модуля той же формы с контекстом.
Нельзя передать: элементы формы, сам объект УправляемаяФорма, ТабличныйДокумент в некоторых сценариях, объекты типа Запрос с открытым результатом, COM-объекты и прочие клиентские сущности. Попытка передать несериализуемый тип вызовет ошибку «Ошибка передачи данных между клиентом и сервером» или аналогичную.
Если нужно передать на сервер содержимое табличной части формы в вызов без контекста, типовой приём — выгрузить её в массив структур на клиенте и собрать таблицу значений уже на сервере, либо использовать реквизит формы типа ТаблицаЗначений и работать через вызов с контекстом.
Работа с объектом на сервере: РеквизитФормыВЗначение
Когда на сервере нужно не просто прочитать данные, а записать объект в базу (провести документ, изменить элемент справочника), используется пара методов формы: РеквизитФормыВЗначение("Объект") превращает данные формы в прикладной объект, а ЗначениеВРеквизитФормы() возвращает изменения обратно в форму.
&НаСервере
Процедура ЗаписатьСИзменениямиНаСервере()
ДокОбъект = РеквизитФормыВЗначение("Объект");
ДокОбъект.Комментарий = "Обработано на сервере";
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры
Без обратного вызова ЗначениеВРеквизитФормы форма не узнает об изменениях, сделанных в объекте на сервере, и пользователь увидит старые данные. Это одна из самых частых ошибок при передаче формы на сервер.
- 1Определите, какие именно данные формы нужны на сервере — не передавайте лишнего.
- 2Если нужен объект формы целиком — создайте процедуру &НаСервере; если только несколько значений — &НаСервереБезКонтекста с параметрами.
- 3Вызовите серверную процедуру из клиентской, передав параметры.
- 4На сервере выполните запрос или запись объекта, при необходимости через РеквизитФормыВЗначение.
- 5Верните результат: через Возврат функции или ЗначениеВРеквизитФормы.
- 6Проверьте в отладчике, что клиент получил ожидаемые значения и форма обновилась.
Ограничения и производительность
Каждый серверный вызов в клиент-серверном варианте — это сетевой пакет. Десять вызовов подряд в цикле обходятся заметно дороже одного вызова с массивом данных. Поэтому правило простое: минимизируйте количество вызовов, а не объём одного вызова (в разумных пределах).
Ещё одно ограничение: серверный вызов из формы — синхронный, интерфейс пользователя в этот момент заблокирован. Если операция длительная (загрузка большого файла, массовая обработка), стоит рассмотреть фоновые задания через ДлительныеОперации из БСП или механизм ФоновыеЗадания.Выполнить() с передачей параметров и последующим опросом результата.
Также помните о транзакциях: если серверная процедура открывает транзакцию и не завершает её корректно из-за исключения, возможны блокировки. Всегда обрабатывайте исключения на сервере через Попытка...Исключение при записи данных.
Типичные ошибки и их диагностика
Первая группа ошибок — обращение к контексту формы из процедуры &НаСервереБезКонтекста. Компилятор выдаст ошибку вида «Переменная не определена (Объект)», потому что реквизиты формы в таком вызове недоступны. Решение — передать нужные значения параметром.
Вторая группа — попытка передать на сервер несериализуемые данные: элементы формы, ТекущиеДанные таблицы формы напрямую (тип ДанныеФормыЭлементКоллекции на сервер без контекста не передаётся). Нужно скопировать значения в структуру на клиенте и передать её.
Третья группа — потеря изменений: разработчик изменил объект на сервере, но забыл ЗначениеВРеквизитФормы или не обновил реквизит формы после вызова без контекста. Симптом — «на сервере всё записалось, а в форме старые данные».
Как проверить результат
В отладчике на серверной точке останова параметры содержат ожидаемые значения
Параметры пустые или Неопределено — ошибка при формировании вызова на клиенте
После вызова переменная-результат содержит новые данные, форма обновилась
Форма показывает старые значения — забыто ЗначениеВРеквизитФормы или присвоение результата
Один вызов на логическую операцию, форма реагирует быстро
Множество вызовов в цикле, заметные паузы в интерфейсе
Объект записан, проведён, в форме актуальные данные и статус
Записано частично или с исключением — нет обработки ошибок в транзакции
Частые вопросы
Можно ли передать саму форму (УправляемаяФорма) на сервер?
Нет. Объект УправляемаяФорма существует только на клиенте и не сериализуется. На сервер передаются только данные: реквизиты формы (автоматически при вызове &НаСервере) или явные параметры (при вызове &НаСервереБезКонтекста). Если на сервере нужны значения формы — передавайте их, а не форму.
Что быстрее: &НаСервере или &НаСервереБезКонтекста?
Вызов без контекста обычно эффективнее: платформа передаёт только указанные параметры, а не всё состояние формы. На формах с большими таблицами и множеством реквизитов разница заметна. Но если нужно работать с объектом формы целиком, вызов с контекстом проще и оправдан.
Как передать табличную часть формы в вызов без контекста?
На клиенте выгрузите строки в массив структур (обойдите коллекцию и скопируйте нужные поля), передайте массив параметром, а на сервере при необходимости соберите из него таблицу значений. Альтернатива — использовать вызов &НаСервере и работать с реквизитом формы напрямую.
Почему возникает ошибка «Ошибка передачи данных между клиентом и сервером»?
Чаще всего потому, что в параметрах или возвращаемом значении есть несериализуемый тип: элемент формы, ДанныеФормыЭлементКоллекции, COM-объект или другой клиентский объект. Проверьте типы всех передаваемых значений и замените проблемные на структуры, массивы или ссылки.
Как выполнить длительную серверную операцию, чтобы форма не зависала?
Используйте фоновые задания: запустите выполнение через ФоновыеЗадания.Выполнить (или обёртку ДлительныеОперации из БСП), передав параметры, а на клиенте периодически проверяйте завершение через обработчик ожидания. После завершения заберите результат из временного хранилища и обновите форму.
Можно ли вызывать серверные процедуры формы из другой формы?
Напрямую — нет, серверные методы формы доступны только внутри её модуля. Для обмена между формами используйте общие серверные модули, параметры при открытии формы, Оповестить() и ОбработкаОповещения, либо передачу данных через временное хранилище.
Что важно запомнить
Форма на сервер не передаётся — передаются только её данные. Используйте &НаСервере, когда нужен объект формы целиком, и &НаСервереБезКонтекста для точечных операций с явными параметрами. Минимизируйте количество вызовов, возвращайте изменения через ЗначениеВРеквизитФормы, а длительные операции выносите в фоновые задания.