При разработке функционала на платформе 1С:Предприятие 8.3 часто возникает задача вынести общую логику обработки формы в общий модуль. Однако при попытке вызвать процедуру серверного общего модуля из клиентского общего модуля с передачей объекта формы разработчики сталкиваются с ошибками платформы. Разберем детально, почему это происходит и как правильно организовать архитектуру взаимодействия клиентского и серверного кода.
Проанализируем технические особенности работы управляемых форм в клиент-серверной архитектуре 1С:
УправляемаяФорма (как клиентский экземпляр, так и контекст на сервере) не поддерживает XDTO-сериализацию и маршалинг. Это означает, что форму физически невозможно передать в качестве параметра при вызове с клиента на сервер через общий модуль с признаком «Вызов сервера». При попытке передачи платформа сгенерирует исключение о недопустимом типе параметра.ЭтотОбъект) можно только внутри контекстных серверных процедур самой формы (с директивой &НаСервере). Общий серверный модуль не имеет прямого доступа к открытой на клиенте форме.Если логика обязательно требует передачи именно серверного контекста формы в общий модуль, необходимо организовать сквозную цепочку вызовов. Выясним, как взаимодействуют процедуры в этом случае:
&НаСервере, перенося выполнение в серверный контекст формы.ЭтотОбъект (серверный контекст формы).Посмотрим на пример реализации кода в модуле формы:
&НаКлиенте
Экспортная Процедура ВыполнитьОбработкуФормыКлиент() Экспорт
ВыполнитьОбработкуФормыНаСервере();
КонецПроцедуры
&НаСервере
Процедура ВыполнитьОбработкуФормыНаСервере()
// Передаем контекст текущей формы в общий серверный модуль
МойСерверныйМодуль.ОбработатьКонтекстФормы(ЭтотОбъект);
КонецПроцедуры
Теперь рассмотрим реализацию принимающей процедуры в общем серверном модуле МойСерверныйМодуль:
Процедура ОбработатьКонтекстФормы(ФормаКонтекст) Экспорт
// Здесь доступен полный контекст серверной формы
Реквизит = ФормаКонтекст.Объект;
// Выполнение необходимых серверных действий
КонецПроцедуры
А вызов из общего клиентского модуля будет выглядеть следующим образом:
Процедура ОбработатьСобытие(Форма) Экспорт
// Вызываем экспортный клиентский метод формы
Форма.ВыполнитьОбработкуФормыКлиент();
КонецПроцедуры
Прямое внедрение процедур в текст типовых форм (особенно путем парсинга исходных файлов) несет высокие риски при последующих обновлениях конфигурации. Рассмотрим более надежные и стандартизированные способы решения задачи.
Если конфигурация типовая и находится на поддержке, вместо правки основной конфигурации заимствуем форму в расширение. В модуле формы расширения перехватываем нужное событие или добавляем серверный метод через аннотации:
&Вместо("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ПродолжитьВызов(Отказ, СтандартнаяОбработка);
МойСерверныйМодульРасширения.ОбработатьФорму(ЭтотОбъект);
КонецПроцедуры
В большинстве случаев серверному коду не требуется весь контекст формы целиком. Гораздо эффективнее передавать только необходимые данные:
Ссылка, массив выбранных строк, значения ключевых полей).Ссылка.ПолучитьОбъект() или запросы и возвращаем результат клиенту.Посмотрим на пример такого взаимодействия:
// В общем клиентском модуле
Процедура ОбработатьДанныеФормы(Форма) Экспорт
Параметры = Новый Структура;
Параметры.Вставить("СсылкаНаДокумент", Форма.Объект.Ссылка);
Параметры.Вставить("Комментарий", Форма.Объект.Комментарий);
Результат = МойСерверныйМодульВызовСервера.ВыполнитьОперацию(Параметры);
// Применяем результат на клиенте
Форма.Элементы.ГруппаРезультат.Видимость = Результат.Успешно;
КонецПроцедуры
Такой подход полностью устраняет зависимость от модулей форм, сохраняет чистоту архитектуры и не создает проблем при обновлении типовых конфигураций.