При переводе старых конфигураций 1С (работающих в режиме обычного приложения) на управляемые формы разработчики часто сталкиваются с крайне странным поведением системы. Кажется, что при записи или проведении документа из новой управляемой формы управление вообще не передается в модуль объекта. Предопределенные обработчики событий, такие как ПередЗаписью, ПриЗаписи или ОбработкаПроведения, словно игнорируются платформой, хотя сам документ успешно записывается и даже делает движения по регистрам.
В этой статье мы подробно разберем, почему возникает эта иллюзия, в чем кроется принципиальное различие работы обычных и управляемых форм, а также по шагам настроим систему для правильной разработки и отладки.
Для того чтобы понять суть проблемы, нам необходимо проанализировать архитектурные различия между обычным и управляемым режимами работы платформы «1С:Предприятие».
В обычном приложении (при работе в режиме толстого клиента с обычными формами) вся работа с объектами базы данных происходит непосредственно на рабочей станции пользователя. Модуль объекта (документа или справочника) компилируется и выполняется на клиенте. Все предопределенные события выполняются в клиентском контексте, и обычный клиентский отладчик без труда перехватывает любые точки останова в модуле объекта.
В управляемых формах (даже если они запущены внутри обычного приложения в режиме толстого клиента) действует жесткая трехзвенная архитектура. Сама форма отображается на клиенте, но любая работа с объектной техникой (запись, проведение, изменение реквизитов) принудительно переносится на сервер. Когда мы нажимаем кнопку «Провести и закрыть» в управляемой форме, платформа совершает серверный вызов. Модуль объекта компилируется на сервере, и все его обработчики событий выполняются исключительно в серверном контексте.
Если в этот момент движения документа успешно формируются, это означает только одно: код в модуле объекта выполняется штатно. Тот факт, что управление «не переходит» в процедуры модуля с точки зрения разработчика, обычно связан исключительно с тем, что в Конфигураторе не настроена или не подключена отладка на сервере приложений.
Для того чтобы точки останова в модуле объекта при записи из управляемой формы начали срабатывать, нам нужно убедиться, что сервер 1С запущен в режиме отладки, а Конфигуратор подключен к серверным сессиям. Выполним следующие действия:
По умолчанию служба сервера 1С (ragent) функционирует в рабочем режиме без поддержки отладки. Чтобы включить отладку в операционной системе Windows, нам потребуется изменить параметры запуска службы в системном реестре:
regedit в строке выполнения).HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\1C:Enterprise 8.3 Server Agent (название ветки может незначительно отличаться в зависимости от версии платформы).ImagePath.-debug. Например, строка должна выглядеть так:
"C:\Program Files\1cv8\8.3.22.1709\bin\ragent.exe" -srvc -agent -regport 1541 -port 1540 -range 1560:1591 -debug
Даже если сервер запущен с ключом отладки, Конфигуратор не всегда автоматически перехватывает серверные вызовы. Нам необходимо явно указать ему это делать:
Если Конфигуратор и сервер приложений запущены на разных физических компьютерах, необходимо убедиться, что брандмауэр (файрвол) на сервере и на компьютере разработчика не блокирует порты отладки (по умолчанию это диапазон TCP-портов с 1560 по 1591). При необходимости добавьте соответствующие правила для входящих и исходящих соединений.
Сообщить() на сервереЧасто в процессе локализации проблемы разработчики пытаются использовать метод быстрого визуального контроля, вставляя вызов Сообщить("Я тут!") в процедуры модуля объекта. В среде разработчиков старой школы бытует ошибочное мнение, что выведенное на сервере сообщение «потеряется» и не дойдет до клиента.
Выясним истинную причину работы этого механизма. В платформе «1С:Предприятие 8» реализована сквозная доставка сообщений. Все текстовые сообщения, сформированные на сервере с помощью метода Сообщить(), помещаются в специализированный буфер текущего сеанса. После успешного завершения серверного вызова и возврата управления на клиентскую сторону этот буфер передается клиенту, и сообщения отображаются на экране пользователя в стандартной панели сообщений.
Исключения из этого правила крайне редки:
ЗаписьЖурналаРегистрации).Поэтому использование Сообщить() в модуле объекта — вполне рабочий способ проверить, выполняется ли код на самом деле, если отладчик по каким-то причинам не настроен.
Еще одна реальная причина, по которой код в модуле объекта может игнорироваться при вызове из управляемой формы, — это некорректное использование директив компиляции препроцессора в конфигурациях, созданных под обычные формы.
Рассмотрим пример типичной структуры старого модуля объекта:
#Если Клиент Тогда
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверка заполнения реквизитов и бизнес-логика
Если Не ЗначениеЗаполнено(Контрагент) Тогда
Отказ = Истина;
Сообщить("Не заполнен контрагент!");
КонецЕсли;
КонецПроцедуры
#КонецЕсли
Проанализируем эту ситуацию. Когда запись объекта инициируется из обычной клиентской формы, препроцессор видит инструкцию #Если Клиент Тогда, компилирует этот блок кода, и проверка успешно отрабатывает. Однако при записи из управляемой формы весь процесс происходит на сервере. Сервер компилирует модуль объекта и полностью игнорирует ветку #Если Клиент Тогда. Код проверки физически не попадает в скомпилированный на сервере модуль, и документ записывается без проверки контрагента!
Для решения этой проблемы необходимо произвести рефакторинг кода модуля объекта:
#Если Клиент Тогда. Проверки должны выполняться на сервере, чтобы гарантировать целостность базы данных вне зависимости от того, откуда записывается объект.Если в процедурах модуля объекта старой конфигурации присутствуют интерактивные вызовы (такие как Вопрос(), Предупреждение(), ВвестиЗначение()), то при попытке записи такого объекта из управляемой формы система вызовет критическое исключение.
Платформа 1С категорически запрещает вызовы любых диалоговых окон на сервере. Чтобы избежать аварийного завершения работы программы, спроектируем правильную архитектуру взаимодействия с пользователем:
Рассмотрим, как правильно организовать интерактивный диалог при записи документа:
ДополнительныеСвойства и принимаем решение о записи или отмене проведения.Пример передачи параметра из модуля формы в модуль объекта при помощи коллекции дополнительных свойств:
// В модуле управляемой формы документа
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
// Добавим специальный параметр в дополнительные свойства
ЭтотОбъект.ДополнительныеСвойства.Вставить("РазрешитьЗаписьБезПроверки", Истина);
КонецПроцедуры
И обработка этого параметра на сервере в модуле объекта:
// В модуле объекта документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
РазрешитьЗапись = Ложь;
Если ДополнительныеСвойства.Свойство("РазрешитьЗаписьБезПроверки") Тогда
РазрешитьЗапись = ДополнительныеСвойства.РазрешитьЗаписьБезПроверки;
КонецЕсли;
Если Не РазрешитьЗапись Тогда
// Выполняем строгие проверки
КонецЕсли;
КонецПроцедуры
Используя данный подход, мы полностью разделяем интерфейсную (клиентскую) часть работы и серверную бизнес-логику, обеспечивая стабильную работу кода как в обычных, так и в управляемых формах приложения.