Разработчики, только начинающие свой путь в программировании на управляемых формах 1С, часто сталкиваются с неприятной ошибкой при попытке вызвать методы ПоказатьПредупреждение, ПоказатьВопрос или старый метод Предупреждение из серверного контекста. Платформа в этом случае выдает системную ошибку, сообщая, что данный метод не может быть выполнен на сервере. Для предотвращения подобных архитектурных ошибок можно использовать систему для автоматического поиска некорректных вызовов в модулях.
В этой статье мы подробно разберем, почему существует это ограничение, проанализируем архитектуру управляемого приложения и рассмотрим несколько эффективных и современных способов организации взаимодействия сервера с пользователем.
Для того чтобы понять причину этого ограничения, давайте проанализируем классическую клиент-серверную архитектуру 1С. Управляемое приложение четко разделяет код, исполняемый на стороне пользователя (на клиенте), и код, выполняемый на стороне сервера СУБД или сервера приложений 1С.
Клиентское приложение — это то, что видит пользователь на своем мониторе. Здесь работает интерактивный интерфейс, отображаются формы, кнопки и диалоговые окна. Сервер же — это мощная вычислительная машина, у которой физически нет монитора (как шутят опытные разработчики, «сервер слепой»). Сервер занимается только обработкой данных, выполнением запросов и проведением документов. Он не имеет доступа к экранным формам конкретного пользователя.
Если бы платформа позволяла вызывать диалоговое окно непосредственно из серверного кода, то серверный процесс заблокировался бы в ожидании ответа пользователя, который этот вопрос даже физически не смог бы увидеть. Именно поэтому интерактивные функции доступны исключительно в процедурах и функциях с директивой выполнения &НаКлиенте.
Что же делать, если нам необходимо выполнить проверку данных на сервере и, в случае обнаружения ошибок, показать пользователю предупреждение? Правильный подход заключается в разделении логики на две части:
Рассмотрим детальный пример реализации этой схемы на встроенном языке 1С:
&НаКлиенте
Процедура ВыполнитьОперацию(Команда)
// Шаг 1: Вызываем серверную функцию для проведения проверки
РезультатПроверки = ПроверитьВозможностьОперацииНаСервере();
// Шаг 3: Анализируем результат на клиенте и выводим предупреждение
Если РезультатПроверки.ЕстьОшибки Тогда
// Используем стандартный асинхронный метод вывода предупреждения
ПоказатьПредупреждение(, РезультатПроверки.ТекстОшибки, , "Внимание!");
Возврат;
КонецЕсли;
// Если все хорошо, продолжаем выполнение алгоритма на клиенте
ПоказатьПредупреждение(, "Проверка успешно пройдена, операция завершена!", , "Успех");
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьВозможностьОперацииНаСервере()
// Шаг 2: Выполняем логику на сервере
СтруктураРезультата = Новый Структура("ЕстьОшибки, ТекстОшибки", Ложь, "");
// Пример бизнес-логики: проверка остатков или статуса контрагента в базе данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Заблокирован КАК Заблокирован
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Ссылка = &Ссылка";
// Предположим, у нас есть ссылка на проверяемого контрагента
// Запрос.УстановитьПараметр("Ссылка", ТекущийКонтрагент);
// Выборка = Запрос.Выполнить().Выбрать();
// Если по результатам запроса партнер заблокирован, заполняем структуру
ИмитацияБлокировки = Истина; // Для примера
Если ИмитацияБлокировки Тогда
СтруктураРезультата.ЕстьОшибки = Истина;
СтруктураРезультата.ТекстОшибки = "Внимание! Выбранный контрагент заблокирован в системе. Операция невозможна.";
КонецЕсли;
Возврат СтруктураРезультата;
КонецФункции
Ситуация усложняется, когда нам нужно задать пользователю последовательно несколько вопросов. Например: «Вы уверены?», а затем после дополнительных проверок на сервере: «Точно уверены?». Раньше разработчикам приходилось использовать сложный механизм обратного вызова через объект ОписаниеОповещения, что превращало читаемый код в запутанную цепочку («макаронный код»).
Начиная с версии платформы 8.3.18, в 1С появился современный асинхронный механизм программирования с использованием модификатора Асинх и оператора Ждать. Это позволяет писать последовательный и понятный код, даже если внутри него происходят обращения к серверу и интерактивные опросы пользователя.
Давайте посмотрим, как изящно решить задачу последовательных вопросов с помощью этого механизма:
&НаКлиенте
Асинх Процедура ВыполнитьМножественныйОпрос(Команда)
// 1. Проверяем первое условие на сервере
НуженПервыйВопрос = ПроверитьПервоеУсловиеНаСервере();
Если НуженПервыйВопрос Тогда
// Ожидаем ответ пользователя, не блокируя интерфейс и не создавая лишних процедур
Ответ = Ждать ПоказатьВопросАсинх(, "Вы уверены, что хотите продолжить операцию?", РежимДиалогаВопрос.ДаНет);
Если Ответ <> КодВозвратаДиалога.Да Тогда
Возврат; // Пользователь отказался
КонецЕсли;
КонецЕсли;
// 2. Проверяем второе условие на сервере
НуженВторойВопрос = ПроверитьВтороеУсловиеНаСервере();
Если НуженВторойВопрос Тогда
ОтветВторой = Ждать ПоказатьВопросАсинх(, "Внимание, это действие необратимо! Вы ТОЧНО уверены?", РежимДиалогаВопрос.ДаНет);
Если ОтветВторой <> КодВозвратаДиалога.Да Тогда
Возврат;
КонецЕсли;
КонецЕсли;
// 3. Если все подтверждения получены, выполняем финальное действие на сервере
ВыполнитьЗаписьДанныхНаСервере();
Ждать ПоказатьПредупреждениеАсинх(, "Операция успешно выполнена!");
КонецПроцедуры
Важное примечание: Обратите внимание, что мы использовали методы с суффиксом Асинх (ПоказатьВопросАсинх и ПоказатьПредупреждениеАсинх). Они возвращают специальный объект типа Обещание, выполнение которого приостанавливает выполнение процедуры на строке с оператором Ждать до тех пор, пока пользователь не нажмет кнопку в окне диалога.
Важно понимать различие между интерактивными диалогами (которые требуют от пользователя нажать кнопку для продолжения работы) и информационными сообщениями. Если вам нужно просто вывести текст ошибки или лог выполнения операции без остановки работы системы, делать это с сервера можно и нужно.
Для этих целей в 1С прекрасно работают встроенный метод Сообщить() и специализированный объект ПользовательскоеСообщение.
Когда вы вызываете метод Сообщить() на сервере, платформа не прерывает работу алгоритма. Она собирает все отправленные сообщения в специальный пул на сервере и, как только управление возвращается клиенту, автоматически отображает их в панели сообщений формы.
Давайте рассмотрим пример использования объекта ПользовательскоеСообщение на сервере с привязкой к конкретному реквизиту формы, чтобы пользователь сразу увидел, где именно допущена ошибка:
&НаСервере
Процедура ПроверитьИЗаписатьДанныеНаСервере()
// Проверяем заполнение реквизитов на сервере
Если Не ЗначениеЗаполнено(Объект.Организация) Тогда
// Создаем структурированное сообщение об ошибке
Сообщение = Новый ПользовательскоеСообщение;
Сообщение.Текст = "Необходимо заполнить организацию!";
Сообщение.Поле = "Объект.Организация"; // Указываем конкретное поле на форме
Сообщение.ПутьКДанным = "Объект";
// Отправляем сообщение на клиент
Сообщение.Сообщить();
КонецЕсли;
КонецПроцедуры
При таком подходе на клиенте сообщение не просто появится в общем списке внизу экрана, а отобразится в виде наглядного всплывающего красного облачка непосредственно рядом с полем ввода организации.
Если серверная операция занимает длительное время (например, обработка тяжелого отчета или загрузка большого файла), блокировать интерфейс пользователя категорически не рекомендуется. В таких ситуациях в типовых конфигурациях на базе Библиотеки стандартных подсистем (БСП) используется механизм «Длительные операции». Для улучшения визуального отклика системы в такие моменты подойдёт инструмент для визуализации процесса выполнения фоновых заданий.
Алгоритм выглядит следующим образом:
Иногда разработчики предлагают использовать для этих целей Систему взаимодействия (встроенный мессенджер 1С). Действительно, этот инструмент позволяет отправлять мгновенные сообщения с сервера конкретному клиенту. Однако стоит учитывать, что Система взаимодействия требует развертывания отдельного сервера или наличия подписки на облачные сервисы 1С, поэтому использовать ее для стандартных диалогов внутри одной формы считается избыточным решением.
Подводя итог, помните золотое правило разработки управляемого приложения 1С: интерактив и общение с пользователем происходят только на клиенте, а расчеты и работа с базой данных — только на сервере. Правильно распределяя роли между клиентским и серверным контекстом, вы сможете писать надежный, быстрый и удобный для пользователей код.