При анализе типовых конфигураций или кода Библиотеки стандартных подсистем (БСП) разработчики нередко сталкивались с парадоксальной картиной: общий клиентский модуль обращается напрямую к процедуре управляемой формы через точку, однако в самом модуле формы у вызываемой процедуры отсутствует ключевое слово Экспорт. Более того, подобный код успешно компилировался и выполнялся без ошибок времени выполнения.
Рассмотрим пример такого вызова из подсистемы управления контактной информацией:
// Вызов из клиентского общего модуля:
Форма.Подключаемый_ОбновитьКонтактнуюИнформацию(Результат);
В модуле самой управляемой формы процедура объявлена следующим образом:
&НаСервере
Процедура Подключаемый_ОбновитьКонтактнуюИнформацию(Результат)
УправлениеКонтактнойИнформацией.ОбновитьКонтактнуюИнформацию(ЭтотОбъект, Объект, Результат);
КонецПроцедуры
Разберем детально, почему платформа допускала такое поведение, почему этот механизм перестал работать в современных версиях и как корректно реализовывать взаимодействие с формой согласно стандартам разработки 1С.
Проанализируем архитектуру вызова, чтобы понять физику процесса. В платформе «1С:Предприятие 8.3» управляемая форма разделена на клиентскую и серверную части. На клиенте разработчик оперирует объектом-ссылкой УправляемаяФорма, который выступает в роли клиентского прокси.
В версиях платформы до 8.3.12 включительно существовала специфика диспетчеризации контекстных серверных вызовов:
Форма.ИмяМетода() с клиента среда исполнения определяла, что указанный метод не зарегистрирован в таблице клиентских экспортов формы, и автоматически транслировала вызов в контекстный серверный запрос.Экспорт не выполнялась, если метод имел директиву компиляции &НаСервере.Экспорт с клиента было нельзя — на клиенте таблица экспортных методов проверялась строго. Также было невозможно вызвать внутренний метод формы из серверного модуля, так как на сервере форма не существует в виде отдельного доступного COM- или API-объекта вне своего контекста.Таким образом, возможность вызова неэкспортных серверных процедур формы являлась недокументированной особенностью работы прокси-объекта управляемой формы при переходе контекста «клиент — сервер».
Полагаться на недокументированные возможности в промышленной разработке рискованно. Начиная с версии платформы 8.3.13 (а также в базах, где режим совместимости установлен на уровень 8.3.13 и выше), данная брешь была полностью устранена разработчиками платформы «1С».
Теперь при попытке внешнего обращения к неэкспортной процедуре управляемой формы платформа незамедлительно генерирует штатное исключение:
Метод объекта не обнаружен (<ИмяМетода>)
Вслед за платформой изменилась и библиотека БСП. В версиях БСП 3.0 и выше документация и шаблоны внедрения подсистем были скорректированы: все подключаемые обработчики форм (такие как Подключаемый_ОбновитьКонтактнуюИнформацию, Подключаемый_ВыполнитьКомандуНаСервере и др.) теперь в обязательном порядке содержат ключевое слово Экспорт.
С точки зрения стандартов разработки фирмы «1С», управляемая форма не должна выступать поставщиком API для внешних механизмов. Модуль формы предназначен исключительно для управления элементами интерфейса и связи пользователя с прикладными данными.
Размещение процедур с директивами &НаСервере Экспорт в модуле формы считается нежелательной практикой по следующим причинам:
Выясним, какими способами следует организовывать взаимодействие с формой и переиспользование кода в современных конфигурациях.
Если мы разрабатываем собственную конфигурацию или дорабатываем форму, снятую с поддержки, и необходимо быстро восстановить работоспособность типового шаблона БСП, добавим ключевое слово Экспорт:
&НаСервере
Процедура Подключаемый_ОбновитьКонтактнуюИнформацию(Результат) Экспорт
УправлениеКонтактнойИнформацией.ОбновитьКонтактнуюИнформацию(ЭтотОбъект, Объект, Результат);
КонецПроцедуры
Если требуется вызов с клиента, безопаснее объявить экспортную клиентскую процедуру, которая уже внутри модуля формы обратится к закрытой серверной части:
&НаКлиенте
Процедура ОбновитьДанныеФормы(Результат) Экспорт
ОбновитьДанныеФормыНаСервере(Результат);
КонецПроцедуры
&НаСервере
Процедура ОбновитьДанныеФормыНаСервере(Результат)
// Серверная обработка данных без прямого экспорта во внешний мир
КонецПроцедуры
Наиболее архитектурно правильный подход — изоляция прикладной логики от экранных форм. Алгоритмы пересчета цен, валидации, заполнения табличных частей выносятся в серверные общие модули. В качестве параметров процедура принимает данные объекта или структуру:
// В общем серверном модуле РасчетЦенСервер:
Процедура ПересчитатьЦены(ДанныеТабличнойЧасти, ПараметрыПересчета) Экспорт
Для Каждого СтрокаТЧ Из ДанныеТабличнойЧасти Цикл
СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЦикла;
КонецПроцедуры
// В модуле формы или внешней обработке:
РасчетЦенСервер.ПересчитатьЦены(Объект.Товары, Новый Структура("Валюта", Объект.Валюта));
Такой код одинаково доступен как для управляемой формы документа, так и для внешних обработок заполнения или регламентных заданий без обращения к контексту открытых окон.
Если одной форме требуется уведомить другую об изменениях, избегаем прямых вызовов методов. Используем платформенный механизм оповещений:
Оповестить("ОбновленаКонтактнаяИнформация", Результат, ЭтотОбъект);
ОбработкаОповещения:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ОбновленаКонтактнаяИнформация" Тогда
ОбновитьКонтактнуюИнформациюНаСервере(Параметр);
КонецЕсли;
КонецПроцедуры
Использование оповещений полностью устраняет жесткую связность между модулями и исключает ошибки поиска методов.
Когда типовая конфигурация находится на полной поддержке и внесение изменений в код формы запрещено, неэкспортные методы невозможно вызвать через внешние обработки. В этом случае задачу решаем с помощью механизма расширений конфигурации:
&После или &Вместо:
&Вместо("УдалитьТоварыБезИзмененныхЦенНаСервере")
Процедура Расш_УдалитьТоварыБезИзмененныхЦенНаСервере()
// Вызов оригинального метода формы
ПродолжитьВызов();
// Дополнительная логика расширения
КонецПроцедуры
Такой подход обеспечивает устойчивость доработок при последующих обновлениях типовой конфигурации и гарантирует корректную работу на актуальных версиях платформы 1С.