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

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

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

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

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

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

Как устроен клиент-серверный вызов в управляемом приложении

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

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

Вызов серверной процедуры в модуле формы

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

&НаКлиенте

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

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

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

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

&НаСервере

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

// здесь можно выполнять запросы, обращаться к данным

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

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

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

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

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

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

Вызов выглядит как обращение к экспортной процедуре модуля:

&НаКлиенте

Процедура ПриОткрытии(Отказ)

Остаток = СкладскойУчетСервер.ПолучитьОстаток(Номенклатура, Склад);

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

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

Порядок действий для общего модуля
  1. 1
    Создайте общий модуль, например РасчетыСервер
  2. 2
    В свойствах включите флаги «Сервер» и «Вызов сервера»
  3. 3
    Напишите функцию с ключевым словом Экспорт
  4. 4
    Из клиентской процедуры вызовите РасчетыСервер.ИмяФункции(Параметры)
  5. 5
    Проверьте, что все параметры — сериализуемые типы

Ограничения на параметры и возвращаемые значения

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

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

Если нужно вернуть несколько значений, упакуйте их в структуру. Для больших результатов (например, длительных отчётов) используйте временное хранилище: серверная процедура помещает данные через ПоместитьВоВременноеХранилище и возвращает только адрес.

Асинхронный вызов и длительные операции

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

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

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

Способы вызова сервера

&НаСервере в форме

Подходит для логики конкретной формы. Минус: передаёт всю форму на сервер при каждом вызове.

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

Быстрее, данные формы недоступны. Хорош для простых функций с параметрами.

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

Для переиспользуемой логики. Требует флага «Вызов сервера» и экспортных процедур.

Фоновое задание

Для длительных операций. Не блокирует интерфейс, но требует опроса результата.

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

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

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

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

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

Как проверить, что вызов работает правильно

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

Для диагностики количества серверных вызовов используйте замер производительности (Отладка → Замер производительности) — там видно, сколько раз и какие процедуры вызывались. Если на одно действие пользователя приходятся десятки вызовов сервера, логику стоит пересобрать в одну серверную процедуру.

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

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

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

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

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

Ошибка «процедура не определена» — проверьте Экспорт и флаг «Вызов сервера»

Передаваемые параметры
Норма

Ссылки, примитивы, структуры, таблицы значений

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

СправочникОбъект, Запрос, несохранённые объекты

Скорость работы формы
Норма

Один-два серверных вызова на действие пользователя

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

Вызовы в цикле, десятки обращений на одну операцию

Итог

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

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

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

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

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

Чем &НаСервере отличается от &НаСервереБезКонтекста?

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

Как вернуть с сервера несколько значений?

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

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

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

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

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

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

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