Разработка и Конфигурация · 12 мин
1С: как вызвать клиентскую процедуру с сервера
Как в 1С вызвать клиентскую процедуру с сервера: оповещения, обработчики ожидания, асинхронные методы, длительные операции БСП. Примеры кода и типичные ошибки.
Прямой вызов клиентской процедуры из серверного кода в 1С невозможен: серверный контекст не имеет доступа к клиентским модулям, директивам &НаКлиенте и объектам формы на стороне пользователя. Это принципиальное ограничение клиент-серверной архитектуры платформы, а не недоработка. Однако задача «сообщить клиенту результат серверной работы» решается несколькими штатными механизмами.
Основные инструменты — оповещения (ОписаниеОповещения), обработчики ожидания, асинхронные методы с обещаниями, а в конфигурациях на БСП — подсистема длительных операций. Выбор зависит от того, нужно ли просто вернуть результат в форму, уведомить несколько открытых окон или показать пользователю прогресс длительной обработки.
Ниже разобраны рабочие сценарии с примерами кода, ограничения каждого подхода и типичные ошибки, из-за которых вызов «не срабатывает» или приводит к падению сеанса.
Почему прямой вызов с сервера на клиент невозможен
В клиент-серверном режиме код с директивой &НаСервере выполняется в процессе rphost на сервере 1С:Предприятия, а клиентский код — в процессе тонкого или толстого клиента на рабочем месте пользователя. Между ними существует только один канал взаимодействия: клиент вызывает сервер, сервер возвращает результат. Обратного канала «сервер инициирует вызов клиента» в платформе нет.
Из этого следует практический вывод: любая схема «вызова клиентской процедуры с сервера» на самом деле строится как «клиент спросил — сервер ответил — клиент обработал ответ». Даже механизмы, которые выглядят как обратный вызов (например, оповещения), технически выполняются уже после возврата управления на клиент.
Попытка обойти ограничение — например, объявить процедуру с директивой &НаКлиентеНаСервереБезКонтекста и обратиться к элементам формы — приведёт к ошибке компиляции или выполнения, потому что в серверном вызове объектов клиентского интерфейса просто не существует.
Возврат результата через оповещение: базовый сценарий
Самый частый случай: на клиенте нужно выполнить серверную логику и по её результату запустить клиентскую процедуру. Правильный шаблон — серверная процедура возвращает значение, а клиент после вызова сам решает, что делать дальше, или использует ВыполнитьОбработкуОповещения.
&НаКлиенте
Процедура КнопкаВыполнить(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеВыполненияНаСервере", ЭтотОбъект);
Результат = ВыполнитьНаСервере(ПараметрыЗапроса);
ВыполнитьОбработкуОповещения(Оповещение, Результат);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВыполнитьНаСервере(ПараметрыЗапроса)
// серверная логика, возвращаем сериализуемое значение
Возврат РезультатОбработки;
КонецФункции
&НаКлиенте
Процедура ПослеВыполненияНаСервере(Результат, ДопПараметры) Экспорт
Если Результат.Успех Тогда
ПоказатьПредупреждение(, "Операция завершена");
КонецЕсли;
КонецПроцедуры
Ключевой момент: процедура-обработчик оповещения должна быть объявлена с ключевым словом Экспорт, иначе платформа не сможет её найти по имени. Первый параметр обработчика всегда получает результат, второй — дополнительные параметры, переданные при создании оповещения.
Такая схема полностью синхронна: клиент «замирает» на время серверного вызова. Для быстрых операций это допустимо, для длительных — нужен другой подход, описанный ниже.
Связь между формами и окнами через Оповестить
Если задача — сообщить из серверной логики одной формы в другую открытую форму (например, обновить список после записи объекта), используется метод Оповестить() на клиенте и обработчик ОбработкаОповещения в форме-приёмнике.
&НаКлиенте
Процедура ПослеЗаписиОбъекта(Результат, ДопПараметры) Экспорт
Оповестить("ОбновитьСписокЗаказов", Результат.Ссылка, ЭтотОбъект);
КонецПроцедуры
// В форме списка:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ОбновитьСписокЗаказов" Тогда
Элементы.Список.Обновить();
КонецЕсли;
КонецПроцедуры
Сервер здесь участвует косвенно: он возвращает данные, а клиент рассылает оповещение. Имя события — произвольная строка, договоритесь о едином соглашении об именовании в проекте, иначе при росте числа событий их станет сложно отслеживать.
Длительные операции: фоновые задания и обработчик ожидания
Когда серверная операция занимает заметное время, блокировать клиент нельзя: пользователь увидит «зависшее» окно, а при превышении таймаута вызова получит ошибку. Решение — запустить фоновое задание на сервере, а на клиенте периодически проверять его состояние через ПодключитьОбработчикОжидания.
&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
ИдентификаторЗадания = ЗапуститьФоновоеЗаданиеНаСервере();
ПодключитьОбработчикОжидания("ПроверитьЗавершение", 2, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьЗавершение() Экспорт
Состояние = ПолучитьСостояниеЗадания(ИдентификаторЗадания);
Если Состояние = "Завершено" Тогда
ОтключитьОбработчикОжидания("ПроверитьЗавершение");
ПослеЗавершенияОбработки();
КонецЕсли;
КонецПроцедуры
Идентификатор фонового задания нужно хранить в реквизите формы — локальная переменная потеряется между вызовами обработчика ожидания. Интервал опроса подбирайте разумно: слишком частые обращения (доли секунды) создают лишнюю нагрузку на сервер при массовой работе пользователей.
В конфигурациях на Библиотеке стандартных подсистем вместо ручной схемы используйте готовый механизм: ДлительныеОперации.ВыполнитьВФоне() и ДлительныеОперацииКлиент.ОжидатьЗавершение(). Он сам показывает форму ожидания, опрашивает задание и вызывает ваше оповещение по завершении — включая обработку ошибок и отмену.
- 1Создайте серверную процедуру, которая запускает фоновое задание и возвращает его идентификатор
- 2Сохраните идентификатор в реквизите формы на клиенте
- 3Подключите обработчик ожидания с разумным интервалом (2–5 секунд)
- 4В обработчике проверяйте состояние задания серверным вызовом
- 5При завершении отключите обработчик и вызовите итоговую клиентскую процедуру
- 6Обработайте сценарий ошибки задания — покажите пользователю текст исключения
Асинхронные методы и обещания
В управляемом приложении большинство интерактивных операций (вопросы пользователю, выбор файлов, работа с расширениями) доступны только в асинхронном варианте — через ПоказатьВопрос, НачатьПомещениеФайла и аналоги. Все они принимают ОписаниеОповещения, и это тот же паттерн «сервер ответил — клиент продолжил», только инициатором паузы выступает клиент.
Типовая цепочка выглядит так: клиент спрашивает пользователя → по ответу вызывает сервер → по результату сервера вызывает следующую клиентскую процедуру. Каждое звено оформляется отдельным оповещением. Глубокие цепочки стоит дробить на именованные процедуры, а не вкладывать друг в друга, иначе код становится трудно читать и отлаживать.
Сравнение подходов
Подходит для быстрых серверных вызовов. Ограничение: клиент блокируется на время выполнения.
Подходит для обновления открытых окон после изменения данных. Ограничение: работает только внутри одного сеанса.
Подходит для длительных операций без БСП. Ограничение: всю логику опроса и ошибок пишете сами.
Оптимально, если конфигурация на БСП: готовая форма ожидания, отмена, обработка ошибок. Ограничение: требует встроенной библиотеки.
Ограничения и передача данных между сервером и клиентом
Через границу «сервер — клиент» проходят только сериализуемые значения: примитивные типы, структуры, массивы, таблицы значений, ссылки. Нельзя вернуть на клиент запрос, построитель отчёта, объект СКД с открытым источником или COM-объект, созданный на сервере. Попытка вернуть несериализуемый тип вызовет ошибку передачи данных.
Отдельное ограничение — директива &НаСервереБезКонтекста: такая процедура не видит реквизиты формы. Если серверной логике нужны данные формы, передавайте их параметрами явно или используйте РеквизитФормыВЗначение в контекстном серверном методе. Обратный путь — ЗначениеВРеквизитФормы.
Объём передаваемых данных тоже имеет значение: возврат таблицы на сотни тысяч строк заметно нагрузит канал и память клиента. Возвращайте только то, что реально нужно для отображения или дальнейшей логики, а тяжёлые промежуточные данные оставляйте на сервере (например, во временном хранилище с передачей только адреса).
Проверка результата и отладка
Признак корректно работающей схемы: после серверного вызова управление возвращается на клиент, оповещение срабатывает ровно один раз, а данные в обработчике соответствуют тому, что вернул сервер. Если оповещение не вызывается, проверьте в первую очередь наличие Экспорт у обработчика и точное совпадение имени процедуры строкой.
Для отладки серверной части включите в конфигураторе отладку на сервере (параметр сервера -debug), иначе точки останова в серверном коде не сработают. Состояние фоновых заданий удобно смотреть через консоль заданий или программно — методом ФоновыеЗадания.НайтиПоУникальномуИдентификатору с проверкой свойства Состояние.
Как проверить результат
Обработчик вызван один раз, параметры заполнены
Обработчик не вызывается или приходит ошибка «процедура не обнаружена»
Состояние «Завершено», результат доступен
Состояние «Ошибка» или задание «висит» в активных
На клиенте получены ожидаемые типы и значения
Ошибка сериализации или пустые значения
Что важно запомнить
Прямого вызова клиентской процедуры с сервера в 1С не существует — стройте схему «клиент запросил, сервер вернул, клиент обработал». Для быстрых операций достаточно возврата значения и оповещения, для длительных — фоновые задания с обработчиком ожидания или длительные операции БСП. Обработчики оповещений объявляйте с Экспорт, а через границу сервер-клиент передавайте только сериализуемые данные.
Частые вопросы
Можно ли вызвать клиентскую процедуру из серверного общего модуля?
Нет. Серверный общий модуль выполняется только на сервере и не имеет доступа к клиентскому контексту. Максимум — вернуть из него значение, а клиент, который его вызвал, сам решит, какую клиентскую процедуру запустить дальше.
Как уведомить других пользователей о событии на сервере?
Оповестить() работает только внутри одного сеанса. Для межсеансовых уведомлений используйте систему взаимодействия (если она развёрнута), либо запись события в регистр с периодическим опросом клиентами через обработчик ожидания.
Почему оповещение срабатывает с ошибкой «Процедура не обнаружена»?
Чаще всего обработчик объявлен без ключевого слова Экспорт, либо имя процедуры в ОписаниеОповещения не совпадает с реальным именем с учётом регистра. Также проверьте, что модуль, указанный как владелец оповещения, действительно содержит эту процедуру.
Чем длительные операции БСП лучше ручного фонового задания?
БСП даёт готовую форму ожидания с индикатором, возможность отмены, автоматический опрос задания, передачу ошибок и сообщений пользователю из фонового сеанса. В ручной схеме всё это придётся реализовывать самостоятельно.
Можно ли из фонового задания показать пользователю сообщение?
Напрямую нет — у фонового задания нет клиентского интерфейса. Сообщения, созданные через Сообщить в фоновом сеансе, можно получить на клиенте методом ПолучитьСообщенияПользователю у объекта фонового задания и показать после завершения.
Что передавать с сервера, если результат очень большой?
Поместите результат во временное хранилище на сервере (ПоместитьВоВременноеХранилище) и верните клиенту только адрес. Клиент сможет получить данные по адресу, когда они действительно понадобятся, а при необходимости — передать адрес в другую форму.