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

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

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

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

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

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

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

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

В клиент-серверном режиме код с директивой &НаСервере выполняется в процессе rphost на сервере 1С:Предприятия, а клиентский код — в процессе тонкого или толстого клиента на рабочем месте пользователя. Между ними существует только один канал взаимодействия: клиент вызывает сервер, сервер возвращает результат. Обратного канала «сервер инициирует вызов клиента» в платформе нет.

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

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

Возврат результата через оповещение: базовый сценарий

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

&НаКлиенте

Процедура КнопкаВыполнить(Команда)

Оповещение = Новый ОписаниеОповещения("ПослеВыполненияНаСервере", ЭтотОбъект);

Результат = ВыполнитьНаСервере(ПараметрыЗапроса);

ВыполнитьОбработкуОповещения(Оповещение, Результат);

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

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

Функция ВыполнитьНаСервере(ПараметрыЗапроса)

// серверная логика, возвращаем сериализуемое значение

Возврат РезультатОбработки;

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

&НаКлиенте

Процедура ПослеВыполненияНаСервере(Результат, ДопПараметры) Экспорт

Если Результат.Успех Тогда

ПоказатьПредупреждение(, "Операция завершена");

КонецЕсли;

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

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

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

Связь между формами и окнами через Оповестить

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

&НаКлиенте

Процедура ПослеЗаписиОбъекта(Результат, ДопПараметры) Экспорт

Оповестить("ОбновитьСписокЗаказов", Результат.Ссылка, ЭтотОбъект);

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

// В форме списка:

&НаКлиенте

Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)

Если ИмяСобытия = "ОбновитьСписокЗаказов" Тогда

Элементы.Список.Обновить();

КонецЕсли;

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

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

Длительные операции: фоновые задания и обработчик ожидания

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

&НаКлиенте

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

ИдентификаторЗадания = ЗапуститьФоновоеЗаданиеНаСервере();

ПодключитьОбработчикОжидания("ПроверитьЗавершение", 2, Ложь);

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

&НаКлиенте

Процедура ПроверитьЗавершение() Экспорт

Состояние = ПолучитьСостояниеЗадания(ИдентификаторЗадания);

Если Состояние = "Завершено" Тогда

ОтключитьОбработчикОжидания("ПроверитьЗавершение");

ПослеЗавершенияОбработки();

КонецЕсли;

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

Идентификатор фонового задания нужно хранить в реквизите формы — локальная переменная потеряется между вызовами обработчика ожидания. Интервал опроса подбирайте разумно: слишком частые обращения (доли секунды) создают лишнюю нагрузку на сервер при массовой работе пользователей.

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

Порядок действий для длительной операции
  1. 1
    Создайте серверную процедуру, которая запускает фоновое задание и возвращает его идентификатор
  2. 2
    Сохраните идентификатор в реквизите формы на клиенте
  3. 3
    Подключите обработчик ожидания с разумным интервалом (2–5 секунд)
  4. 4
    В обработчике проверяйте состояние задания серверным вызовом
  5. 5
    При завершении отключите обработчик и вызовите итоговую клиентскую процедуру
  6. 6
    Обработайте сценарий ошибки задания — покажите пользователю текст исключения

Асинхронные методы и обещания

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

Типовая цепочка выглядит так: клиент спрашивает пользователя → по ответу вызывает сервер → по результату сервера вызывает следующую клиентскую процедуру. Каждое звено оформляется отдельным оповещением. Глубокие цепочки стоит дробить на именованные процедуры, а не вкладывать друг в друга, иначе код становится трудно читать и отлаживать.

Сравнение подходов

Возврат значения + ВыполнитьОбработкуОповещения

Подходит для быстрых серверных вызовов. Ограничение: клиент блокируется на время выполнения.

Оповестить() между формами

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

Фоновое задание + обработчик ожидания

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

Длительные операции БСП

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

Ограничения и передача данных между сервером и клиентом

Через границу «сервер — клиент» проходят только сериализуемые значения: примитивные типы, структуры, массивы, таблицы значений, ссылки. Нельзя вернуть на клиент запрос, построитель отчёта, объект СКД с открытым источником или COM-объект, созданный на сервере. Попытка вернуть несериализуемый тип вызовет ошибку передачи данных.

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

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

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

Проверка результата и отладка

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

Для отладки серверной части включите в конфигураторе отладку на сервере (параметр сервера -debug), иначе точки останова в серверном коде не сработают. Состояние фоновых заданий удобно смотреть через консоль заданий или программно — методом ФоновыеЗадания.НайтиПоУникальномуИдентификатору с проверкой свойства Состояние.

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

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

Срабатывание оповещения
Норма

Обработчик вызван один раз, параметры заполнены

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

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

Состояние фонового задания
Норма

Состояние «Завершено», результат доступен

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

Состояние «Ошибка» или задание «висит» в активных

Передача данных
Норма

На клиенте получены ожидаемые типы и значения

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

Ошибка сериализации или пустые значения

Итог

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

Прямого вызова клиентской процедуры с сервера в 1С не существует — стройте схему «клиент запросил, сервер вернул, клиент обработал». Для быстрых операций достаточно возврата значения и оповещения, для длительных — фоновые задания с обработчиком ожидания или длительные операции БСП. Обработчики оповещений объявляйте с Экспорт, а через границу сервер-клиент передавайте только сериализуемые данные.

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

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

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

Как уведомить других пользователей о событии на сервере?

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

Почему оповещение срабатывает с ошибкой «Процедура не обнаружена»?

Чаще всего обработчик объявлен без ключевого слова Экспорт, либо имя процедуры в ОписаниеОповещения не совпадает с реальным именем с учётом регистра. Также проверьте, что модуль, указанный как владелец оповещения, действительно содержит эту процедуру.

Чем длительные операции БСП лучше ручного фонового задания?

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

Можно ли из фонового задания показать пользователю сообщение?

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

Что передавать с сервера, если результат очень большой?

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