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

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

Как выполнить процедуру на сервере в 1С

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

В клиент-серверной архитектуре 1С код может выполняться в двух местах: на клиенте (компьютер пользователя, тонкий или веб-клиент) и на сервере (сервер 1С:Предприятия). Обращение к данным информационной базы — запросы, чтение и запись объектов, обращения к справочникам и документам — возможно только на сервере. Поэтому умение правильно организовать серверный вызов — базовый навык при доработке управляемых форм.

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

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

Где выполняется код: клиент и сервер в 1С

В файловом варианте работы «сервером» условно считается сам процесс клиентского приложения, и разделение кода почти не ощущается. В клиент-серверном варианте тонкий клиент не имеет прямого доступа к СУБД: любой запрос к базе требует обращения к серверу 1С:Предприятия по сети. Каждый такой вызов — это передача данных, ожидание и нагрузка на сервер.

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

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

Как объявить серверную процедуру в модуле формы

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

Пример простейшей серверной процедуры, заполняющей реквизит формы:

&НаСервере

Процедура ЗаполнитьОстаткиНаСервере()

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

Запрос.Текст = "ВЫБРАТЬ Товары.Номенклатура КАК Номенклатура,

|Товары.КоличествоОстаток КАК Остаток

|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Товары";

РезультатЗапроса = Запрос.Выполнить().Выгрузить();

ТаблицаОстатков.Загрузить(РезультатЗапроса);

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

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

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

Вызов серверной процедуры из клиентского кода

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

&НаКлиенте

Процедура ЗаполнитьОстатки(Команда)

ЗаполнитьОстаткиНаСервере();

Элементы.ТаблицаОстатков.Обновить();

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

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

Если серверная процедура используется только как обработчик команды формы, клиентскую «прокладку» можно не писать: в свойствах команды укажите обработчик с директивой &НаСервере, и нажатие кнопки сразу приведёт к серверному вызову. Это сокращает код, но лишает возможности выполнить чисто клиентские действия (например, вопрос пользователю) до обращения к серверу.

bsl
&НаКлиенте
Процедура КомандаРассчитать(Команда)
    Сумма = РассчитатьИтогНаСервере(Объект.Ссылка);
    ПоказатьОповещениеПользователя("Итог: " + Сумма);
КонецПроцедуры

&НаСервереБезКонтекста
Функция РассчитатьИтогНаСервере(ДокументСсылка)
    Возврат ДокументСсылка.Товары.Итог("Сумма");
КонецФункции

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

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

Практическое правило: если процедуре нужен объект документа из формы, передайте в бесконтекстный метод ссылку, а не весь объект. На сервере получите объект через Ссылка.ПолучитьОбъект(), выполните изменения и запишите. Если же нужно изменить именно данные редактируемой формы без переоткрытия — используйте контекстный вызов и работайте с реквизитами формы напрямую.

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

&НаСервере (контекстный)

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

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

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

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

Для логики, общей для нескольких форм и объектов. Требует включённых флагов «Сервер» и «Вызов сервера»; нельзя использовать клиентские типы в экспортных методах.

Серверные процедуры в общих модулях

Когда одна и та же логика нужна в нескольких формах или вызывается из подсистем без формы, её выносят в общий модуль. Чтобы модуль выполнялся на сервере и был доступен для вызова с клиента, в его свойствах должны быть установлены флаги «Сервер» и «Вызов сервера». Флаг «Клиент (управляемое приложение)» при этом снимается.

Вызов из клиентского кода выглядит так:

&НаКлиенте

Процедура ПровестиДокументы(Команда)

КоличествоПроведённых = ОбработкаДокументов.ПровестиЗаПериод(НачалоПериода, КонецПериода);

ПоказатьОповещениеПользователя("Проведено документов: " + КоличествоПроведённых);

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

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

Передача параметров и возврат результата

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

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

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

Функция ПолучитьДанныеКонтрагента(КонтрагентСсылка)

Результат = Новый Структура;

Результат.Вставить("ИНН", КонтрагентСсылка.ИНН);

Результат.Вставить("КПП", КонтрагентСсылка.КПП);

Возврат Результат;

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

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

Проверка выполнения и типичные ошибки

Чтобы убедиться, что код выполняется именно на сервере, включите в конфигураторе отладку серверных вызовов: меню «Сервис → Параметры», флажки отладки по протоколу и разрешение отладки. В кластере серверов отладка должна быть разрешена при запуске службы агента (ключ -debug). После этого точки останова внутри серверных процедур начнут срабатывать.

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

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

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

Точка останова в серверной процедуре
Норма

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

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

Точка не срабатывает — процедура не вызывается или отладка сервера не включена

Скорость выполнения операции
Норма

Один серверный вызов на всю операцию, интерфейс не «подвисает» надолго

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

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

Данные после вызова
Норма

Реквизиты формы обновлены, изменения видны пользователю

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

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

Часто задаваемые вопросы

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

Напрямую — нет: сервер не имеет доступа к клиентскому контексту. Результат серверной работы возвращается клиенту как значение функции или через обновление данных формы. Для фоновых задач используются длительные операции с оповещением клиента о завершении.

Почему серверная процедура не видна из клиентского кода формы?

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

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

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

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

Используйте регламентное задание: в его свойствах указывается экспортная процедура общего серверного модуля. Платформа будет вызывать её на сервере по расписанию без участия пользователя. Для разового запуска подойдёт фоновое задание через метод ФоновыеЗадания.Выполнить.

Почему изменения, сделанные на сервере, не отображаются в форме?

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

Можно ли выполнить произвольный код на сервере из внешней обработки?

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

Итог

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

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