К статье
Практический материал

Разработка и Конфигурация · 12 мин

1С: как передать форму на сервер

Как в 1С передать данные формы на сервер: директивы &НаСервере и &НаСервереБезКонтекста, передача параметров, типичные ошибки и ограничения платформы.

В управляемом приложении 1С форма выполняется на клиенте, а работа с базой данных, запросами и объектами возможна только на сервере. Поэтому типовая задача разработчика — передать данные формы на сервер, выполнить там обработку и вернуть результат обратно. Делается это через серверные процедуры и функции в модуле формы с директивами компиляции &НаСервере и &НаСервереБезКонтекста.

Ключевой момент, который нужно понять сразу: саму форму как объект «передать на сервер» нельзя. На сервер уходят только сериализуемые данные — реквизиты формы, параметры и значения примитивных типов, ссылки, структуры, таблицы значений. Контекст формы (элементы, оформление, свойства окна) существует только на клиенте.

Ниже разобраны оба способа серверных вызовов, различия между ними, ограничения платформы, типичные ошибки и способы проверить, что передача данных работает корректно.

Как устроен вызов сервера из формы

В модуле управляемой формы каждая процедура и функция помечается директивой компиляции: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста или &НаКлиентеНаСервереБезКонтекста. Директива определяет, где будет исполняться код. Когда клиентская процедура вызывает серверную, платформа сериализует переданные параметры, отправляет их на сервер, выполняет код и возвращает результат.

Каждый такой вызов — это сетевое обращение (в клиент-серверном варианте) или как минимум переключение контекста (в файловом). Поэтому серверные вызовы в цикле или при каждом нажатии клавиши — частая причина «тормозов» интерфейса. Правильный подход — собрать данные на клиенте и передать их одним вызовом.

Передача формы через &НаСервере

Процедура с директивой &НаСервере выполняется на сервере, но имеет доступ к контексту формы: реквизитам, их значениям, объекту формы через РеквизитФормыВЗначение() и ЭтаФорма. Фактически платформа сама передаёт состояние реквизитов формы на сервер и после выполнения синхронизирует изменения обратно.

Типовой пример — обработка данных объекта, скажем пересчёт табличной части документа:

&НаКлиенте

Процедура Пересчитать(Команда)

ПересчитатьНаСервере();

КонецПроцедуры

&НаСервере

Процедура ПересчитатьНаСервере()

Объект.Сумма = 0;

Для Каждого Строка Из Объект.Товары Цикл

Строка.Сумма = Строка.Количество * Строка.Цена;

Объект.Сумма = Объект.Сумма + Строка.Сумма;

КонецЦикла;

КонецПроцедуры

Здесь данные формы (реквизит Объект) автоматически доступны на сервере. Это удобно, но есть цена: платформа передаёт весь контекст формы туда и обратно, что на «тяжёлых» формах с десятками реквизитов и большими таблицами даёт заметные накладные расходы.

Передача данных через &НаСервереБезКонтекста

Директива &НаСервереБезКонтекста означает, что процедура не имеет доступа к реквизитам формы. Все нужные данные передаются явно через параметры, а результат возвращается через Возврат или параметры, переданные по ссылке (в 1С значения параметров изменяются, если они не объявлены с Знач).

&НаКлиенте

Процедура РассчитатьЦену(Команда)

НоваяЦена = РассчитатьЦенуНаСервере(Объект.Номенклатура, Объект.Количество);

Объект.Цена = НоваяЦена;

КонецПроцедуры

&НаСервереБезКонтекста

Функция РассчитатьЦенуНаСервере(Номенклатура, Количество)

Запрос = Новый Запрос("ВЫБРАТЬ Цена ИЗ РегистрСведений.Цены

|ГДЕ Номенклатура = &Номенклатура");

Запрос.УстановитьПараметр("Номенклатура", Номенклатура);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

Возврат Выборка.Цена * Количество;

КонецЕсли;

Возврат 0;

КонецФункции

Этот вариант считается предпочтительным: передаются только нужные данные, код легче тестировать, а зависимость от контекста формы отсутствует. На практике в типовых конфигурациях большинство серверных вызовов из форм сделано именно «без контекста».

Сравнение вариантов

&НаСервере

Подходит, когда нужно работать с реквизитами формы или объектом целиком. Ограничение: передаётся весь контекст формы, медленнее на тяжёлых формах.

&НаСервереБезКонтекста

Подходит для точечных операций: запросы, расчёты, проверки. Передаются только параметры — быстрее и чище, но данные формы нужно передавать и возвращать явно.

Общий серверный модуль

Подходит для переиспользуемой логики: вызов из формы процедуры общего модуля с флагом «Сервер». Форма вообще не участвует, передаются только параметры.

Какие данные можно передать на сервер

На сервер из клиентской процедуры формы можно передать: примитивные типы (число, строка, дата, булево), ссылки на объекты базы данных, структуры и соответствия, массивы, таблицы значений (через реквизит формы или преобразование), а также ДанныеФормыСтруктура, если вызов идёт внутри модуля той же формы с контекстом.

Нельзя передать: элементы формы, сам объект УправляемаяФорма, ТабличныйДокумент в некоторых сценариях, объекты типа Запрос с открытым результатом, COM-объекты и прочие клиентские сущности. Попытка передать несериализуемый тип вызовет ошибку «Ошибка передачи данных между клиентом и сервером» или аналогичную.

Если нужно передать на сервер содержимое табличной части формы в вызов без контекста, типовой приём — выгрузить её в массив структур на клиенте и собрать таблицу значений уже на сервере, либо использовать реквизит формы типа ТаблицаЗначений и работать через вызов с контекстом.

Работа с объектом на сервере: РеквизитФормыВЗначение

Когда на сервере нужно не просто прочитать данные, а записать объект в базу (провести документ, изменить элемент справочника), используется пара методов формы: РеквизитФормыВЗначение("Объект") превращает данные формы в прикладной объект, а ЗначениеВРеквизитФормы() возвращает изменения обратно в форму.

&НаСервере

Процедура ЗаписатьСИзменениямиНаСервере()

ДокОбъект = РеквизитФормыВЗначение("Объект");

ДокОбъект.Комментарий = "Обработано на сервере";

ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

ЗначениеВРеквизитФормы(ДокОбъект, "Объект");

КонецПроцедуры

Без обратного вызова ЗначениеВРеквизитФормы форма не узнает об изменениях, сделанных в объекте на сервере, и пользователь увидит старые данные. Это одна из самых частых ошибок при передаче формы на сервер.

Порядок действий
  1. 1
    Определите, какие именно данные формы нужны на сервере — не передавайте лишнего.
  2. 2
    Если нужен объект формы целиком — создайте процедуру &НаСервере; если только несколько значений — &НаСервереБезКонтекста с параметрами.
  3. 3
    Вызовите серверную процедуру из клиентской, передав параметры.
  4. 4
    На сервере выполните запрос или запись объекта, при необходимости через РеквизитФормыВЗначение.
  5. 5
    Верните результат: через Возврат функции или ЗначениеВРеквизитФормы.
  6. 6
    Проверьте в отладчике, что клиент получил ожидаемые значения и форма обновилась.

Ограничения и производительность

Каждый серверный вызов в клиент-серверном варианте — это сетевой пакет. Десять вызовов подряд в цикле обходятся заметно дороже одного вызова с массивом данных. Поэтому правило простое: минимизируйте количество вызовов, а не объём одного вызова (в разумных пределах).

Ещё одно ограничение: серверный вызов из формы — синхронный, интерфейс пользователя в этот момент заблокирован. Если операция длительная (загрузка большого файла, массовая обработка), стоит рассмотреть фоновые задания через ДлительныеОперации из БСП или механизм ФоновыеЗадания.Выполнить() с передачей параметров и последующим опросом результата.

Также помните о транзакциях: если серверная процедура открывает транзакцию и не завершает её корректно из-за исключения, возможны блокировки. Всегда обрабатывайте исключения на сервере через Попытка...Исключение при записи данных.

Типичные ошибки и их диагностика

Первая группа ошибок — обращение к контексту формы из процедуры &НаСервереБезКонтекста. Компилятор выдаст ошибку вида «Переменная не определена (Объект)», потому что реквизиты формы в таком вызове недоступны. Решение — передать нужные значения параметром.

Вторая группа — попытка передать на сервер несериализуемые данные: элементы формы, ТекущиеДанные таблицы формы напрямую (тип ДанныеФормыЭлементКоллекции на сервер без контекста не передаётся). Нужно скопировать значения в структуру на клиенте и передать её.

Третья группа — потеря изменений: разработчик изменил объект на сервере, но забыл ЗначениеВРеквизитФормы или не обновил реквизит формы после вызова без контекста. Симптом — «на сервере всё записалось, а в форме старые данные».

Типичные ошибки
01
Серверные вызовы в цикле — интерфейс зависает из-за множества сетевых обращений; решение: собрать данные в массив и вызвать сервер один раз.
02
Изменение объекта на сервере без ЗначениеВРеквизитФормы — форма показывает устаревшие данные.
03
Передача ДанныеФормыЭлементКоллекции в вызов &НаСервереБезКонтекста — ошибка сериализации; нужно скопировать значения в структуру.
04
Доступ к реквизитам формы из &НаСервереБезКонтекста — ошибка компиляции «Переменная не определена».
05
Длительная операция в синхронном вызове — форма «висит»; для тяжёлых задач используйте фоновые задания.
Контрольные точки

Как проверить результат

Данные дошли до сервера
Норма

В отладчике на серверной точке останова параметры содержат ожидаемые значения

Тревожный признак

Параметры пустые или Неопределено — ошибка при формировании вызова на клиенте

Результат вернулся на клиент
Норма

После вызова переменная-результат содержит новые данные, форма обновилась

Тревожный признак

Форма показывает старые значения — забыто ЗначениеВРеквизитФормы или присвоение результата

Производительность
Норма

Один вызов на логическую операцию, форма реагирует быстро

Тревожный признак

Множество вызовов в цикле, заметные паузы в интерфейсе

Запись объекта
Норма

Объект записан, проведён, в форме актуальные данные и статус

Тревожный признак

Записано частично или с исключением — нет обработки ошибок в транзакции

Частые вопросы

Можно ли передать саму форму (УправляемаяФорма) на сервер?

Нет. Объект УправляемаяФорма существует только на клиенте и не сериализуется. На сервер передаются только данные: реквизиты формы (автоматически при вызове &НаСервере) или явные параметры (при вызове &НаСервереБезКонтекста). Если на сервере нужны значения формы — передавайте их, а не форму.

Что быстрее: &НаСервере или &НаСервереБезКонтекста?

Вызов без контекста обычно эффективнее: платформа передаёт только указанные параметры, а не всё состояние формы. На формах с большими таблицами и множеством реквизитов разница заметна. Но если нужно работать с объектом формы целиком, вызов с контекстом проще и оправдан.

Как передать табличную часть формы в вызов без контекста?

На клиенте выгрузите строки в массив структур (обойдите коллекцию и скопируйте нужные поля), передайте массив параметром, а на сервере при необходимости соберите из него таблицу значений. Альтернатива — использовать вызов &НаСервере и работать с реквизитом формы напрямую.

Почему возникает ошибка «Ошибка передачи данных между клиентом и сервером»?

Чаще всего потому, что в параметрах или возвращаемом значении есть несериализуемый тип: элемент формы, ДанныеФормыЭлементКоллекции, COM-объект или другой клиентский объект. Проверьте типы всех передаваемых значений и замените проблемные на структуры, массивы или ссылки.

Как выполнить длительную серверную операцию, чтобы форма не зависала?

Используйте фоновые задания: запустите выполнение через ФоновыеЗадания.Выполнить (или обёртку ДлительныеОперации из БСП), передав параметры, а на клиенте периодически проверяйте завершение через обработчик ожидания. После завершения заберите результат из временного хранилища и обновите форму.

Можно ли вызывать серверные процедуры формы из другой формы?

Напрямую — нет, серверные методы формы доступны только внутри её модуля. Для обмена между формами используйте общие серверные модули, параметры при открытии формы, Оповестить() и ОбработкаОповещения, либо передачу данных через временное хранилище.

Итог

Что важно запомнить

Форма на сервер не передаётся — передаются только её данные. Используйте &НаСервере, когда нужен объект формы целиком, и &НаСервереБезКонтекста для точечных операций с явными параметрами. Минимизируйте количество вызовов, возвращайте изменения через ЗначениеВРеквизитФормы, а длительные операции выносите в фоновые задания.