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

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

Как передать переменную с клиента на сервер в 1С

Как передать переменную с клиента на сервер в 1С: серверные вызовы, директивы компиляции, сериализация, общие модули и типичные ошибки с примерами кода.

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

Ключевой момент: физически переменная не «передаётся» как объект в памяти — значение сериализуется, переносится на сервер и там воссоздаётся. Поэтому передать можно только те типы, которые платформа умеет сериализовать: примитивы, структуры, массивы, таблицы значений, ссылки. А вот элемент формы или COM-объект передать нельзя.

Где разместить серверную процедуру для приёма значения

Есть два основных места для серверного кода, который вызывается с клиента. Первое — модуль формы с директивой &НаСервере. Такой метод виден только внутри формы и подходит, когда логика относится к конкретному объекту формы и не нужна повторно. Плюс — доступ к реквизитам формы и её данным напрямую.

Второе место — общий модуль с установленными флагами «Сервер» и «Вызов сервера». Без флага «Вызов сервера» клиент просто не увидит этот модуль, и попытка обращения даст ошибку «Метод объекта не обнаружен». Общие модули используют, когда серверная логика нужна из разных форм: расчёты, получение данных, формирование печатных форм.

Базовый пример: вызов серверной процедуры из клиентской

Минимальный рабочий сценарий выглядит так. В общем модуле РаботаСДаннымиСервер (сервер, вызов сервера) создаётся экспортная функция:

// Общий модуль РаботаСДаннымиСервер

Функция ПолучитьОстаток(Номенклатура, Склад) Экспорт

// запрос к базе данных

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Остаток ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки

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

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

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

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

Возврат ?(Выборка.Следующий(), Выборка.Остаток, 0);

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

На клиенте, например в обработчике команды формы, вызываем эту функцию и передаём переменные через параметры:

&НаКлиенте

Процедура ПоказатьОстаток(Команда)

ТекТовар = Объект.Номенклатура;

ТекСклад = Объект.Склад;

Остаток = РаботаСДаннымиСервер.ПолучитьОстаток(ТекТовар, ТекСклад);

Сообщить("Остаток: " + Остаток);

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

Значения ТекТовар и ТекСклад при вызове сериализуются, передаются на сервер, там создаются их копии, с которыми работает серверная функция. Результат возвращается обратно тем же механизмом.

Порядок действий
  1. 1
    Создайте общий модуль, включите флаги «Сервер» и «Вызов сервера»
  2. 2
    Объявите экспортную функцию с параметрами нужных типов
  3. 3
    В клиентской процедуре подготовьте переменные и вызовите функцию
  4. 4
    Проверьте, что все передаваемые значения сериализуемы
  5. 5
    Запустите форму и убедитесь, что результат возвращается корректно

Передача составных данных: структуры, массивы, таблицы значений

Когда нужно передать несколько связанных значений, удобнее упаковать их в структуру, чем перечислять десяток параметров. Структура полностью сериализуется, если все её значения сериализуемы:

&НаКлиенте

Процедура ОтправитьОтбор(Команда)

ПараметрыОтбора = Новый Структура;

ПараметрыОтбора.Вставить("ДатаНачала", ДатаНачала);

ПараметрыОтбора.Вставить("ДатаОкончания", ДатаОкончания);

ПараметрыОтбора.Вставить("Контрагент", Контрагент);

Результат = РаботаСДаннымиСервер.СформироватьДанные(ПараметрыОтбора);

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

Массивы и таблицы значений тоже передаются, но с оговорками. Таблица значений с большим числом строк создаёт заметный трафик между клиентом и сервером. Если нужно передать данные табличной части формы, часто рациональнее использовать Объект.ТабличнаяЧасть.Выгрузить() — получится таблица значений, пригодная для передачи. Либо передать только ссылку на документ и прочитать данные уже на сервере.

Динамические списки, элементы форм, объекты типа ДанныеФормыСтруктура напрямую не передаются. Для реквизитов формы сначала выполняют преобразование, например через РеквизитФормыВЗначение() в серверном контексте формы.

Контекст формы: передача через &НаСервере и параметры формы

Если серверная логика привязана к форме, метод объявляют с директивой &НаСервере прямо в модуле формы. Такой метод имеет доступ к реквизитам формы, поэтому часто передавать переменные вообще не нужно — достаточно прочитать реквизит:

&НаСервере

Процедура ЗаполнитьПоУмолчанию()

// Объект доступен напрямую

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

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

&НаКлиенте

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

ЗаполнитьПоУмолчанию(); // вызов сервера из клиента

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

Другой сценарий — передача данных между формами через параметры открытия. При ОткрытьФорму() параметры передаются в структуре и обрабатываются в ПриСозданииНаСервере открываемой формы. Это тоже передача «с клиента на сервер», только точкой входа выступает создание формы.

Сравнение способов

&НаСервере в модуле формы

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

Общий модуль (сервер, вызов сервера)

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

Параметры при открытии формы

Передача данных новой форме через ОткрытьФорму. Не подходит для обмена внутри уже открытой формы.

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

Платформа сериализует не всё. Перед вызовом сервера стоит проверить типы переменных, иначе получите ошибку «Ошибка передачи данных между клиентом и сервером» или подобную. Ниже — основные ориентиры.

Тип значенияПередаётсяКомментарий
Число, Строка, Дата, БулевоДаПримитивы, ограничений нет
Структура, Массив, СоответствиеДаЕсли вложенные значения сериализуемы
ТаблицаЗначенийДаСледите за объёмом данных
Ссылки на объектыДаПередаётся ссылка, не сам объект
Объекты (ДокументОбъект и т.п.)НетПередавайте ссылку, читайте объект на сервере
Элементы формы, ДанныеФормыНетИспользуйте реквизиты формы или выгрузку

Отдельно стоит сказать про ЗначениеВСтрокуВнутр(): сериализованное внутреннее представление можно передать строкой и восстановить на сервере через ЗначениеИзСтрокиВнутр(). Это рабочий, но тяжёлый приём — применяйте его только когда стандартная передача невозможна, и помните о накладных расходах на размер строки.

Типичные ошибки
01
Вызов общего модуля без флага «Вызов сервера» — ошибка «Метод объекта не обнаружен»
02
Попытка передать ДокументОбъект или элемент формы — ошибка сериализации при вызове
03
Передача огромной таблицы значений при каждом клике — форма начинает тормозить из-за трафика
04
Директива &НаСервереБезКонтекста с обращением к реквизитам формы — метод не видит данные формы
05
Изменение параметра на сервере с ожиданием, что переменная на клиенте изменится — значения копируются, ссылочности нет

Контекстные и бесконтекстные серверные вызовы

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

Практическое правило: если процедуре нужны только несколько значений — делайте её &НаСервереБезКонтекста и передавайте эти значения явно. Если требуется массовая работа с данными формы (заполнение табличной части, преобразование реквизитов) — используйте контекстный вызов.

Также учитывайте, что каждый серверный вызов — это сетевое обращение. Пять вызовов подряд в цикле заметно медленнее одного вызова со структурой параметров. Группируйте обращения к серверу.

Если на клиенте уже есть ссылка на объект, почти всегда выгоднее передать только ссылку и прочитать данные запросом на сервере, чем выгружать и передавать табличные части целиком.
ПЗ
Практическое замечание

Проверка результата и диагностика проблем

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

Если серверная точка останова не срабатывает — почти наверняка проблема в доступности модуля: проверьте флаги «Сервер» и «Вызов сервера», экспортность процедуры и отсутствие ошибок компиляции модуля. Если вызов происходит, но падает с ошибкой сериализации — пройдитесь по типам всех параметров и вложенных значений структур.

Контрольные точки

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

Доступность серверной процедуры
Норма

Точка останова на сервере срабатывает при вызове с клиента

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

Ошибка «Метод объекта не обнаружен» ещё на клиенте

Значения параметров
Норма

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

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

Параметры пустые или ошибка сериализации при вызове

Возврат результата
Норма

Клиент получает ожидаемое значение и форма обновляется

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

Функция возвращает Неопределено или устаревшие данные

Итог

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

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

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

Можно ли изменить клиентскую переменную «по ссылке» из серверной процедуры?

Нет. Значения копируются при серверном вызове, поэтому изменения параметра на сервере не отражаются на клиентской переменной. Возвращайте результат через Возврат и присваивайте его на клиенте явно.

Почему возникает ошибка «Метод объекта не обнаружен» при вызове общего модуля?

Чаще всего в общем модуле не установлен флаг «Вызов сервера», процедура не объявлена с ключевым словом Экспорт или модуль не компилируется из-за синтаксической ошибки. Проверьте эти три пункта в указанном порядке.

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

Используйте Объект.ТабличнаяЧасть.Выгрузить() — полученная таблица значений сериализуется и передаётся параметром. Альтернатива — контекстный серверный вызов &НаСервере, где табличная часть доступна напрямую через объект формы.

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

Если процедуре нужны реквизиты и данные формы — &НаСервере. Если достаточно нескольких переданных значений — &НаСервереБезКонтекста, такой вызов дешевле, поскольку не переносит состояние формы на сервер.

Можно ли передать на сервер COM-объект или картинку из клиента?

COM-объекты и другие несериализуемые типы передать нельзя. Двоичные данные файла передают через временное хранилище: на клиенте помещают файл через НачатьПомещениеФайла, а на сервер передают адрес хранилища, откуда данные забираются методом ПолучитьИзВременногоХранилища.

Замедляет ли работу большое число серверных вызовов?

Да, каждый вызов — отдельное обращение к серверу с сериализацией данных. Если в цикле или при интерактивных действиях пользователя выполняется много вызовов, объедините их в один, передав набор параметров структурой или массивом.