Как вызвать экспортный метод модуля объекта внешней обработки без передачи контекста формы

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке сложных управляемых форм на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с проблемой производительности. Когда форма перегружена данными (большие таблицы, деревья, множество реквизитов), любой стандартный вызов серверной процедуры (директива &НаСервере) приводит к передаче всего этого массива данных между клиентом и сервером. В этой статье мы разберем ситуацию, когда необходимо вызвать метод, находящийся в модуле объекта внешней обработки, максимально «дешево» с точки зрения трафика и нагрузки на систему.

Постановка задачи и анализ ограничений

Рассмотрим ситуацию: у нас есть внешняя обработка. В ее модуле объекта реализована сложная бизнес-логика в экспортной процедуре. Нам нужно вызвать эту логику из модуля управляемой формы. Стандартный путь через РеквизитФормыВЗначение("Объект") требует контекстного вызова, так как сам метод РеквизитФормыВЗначение является методом объекта УправляемаяФорма и неразрывно связан с ее состоянием. Если форма «тяжелая», этот процесс будет медленным. Наша цель — реализовать вызов через &НаСервереБезКонтекста.

Решение 1. Использование неконтекстного вызова и временного хранилища

Поскольку мы не можем вызвать модуль объекта напрямую с клиента, нам необходимо «собрать» этот объект на сервере заново в неконтекстной процедуре. Проанализируем алгоритм действий:

  1. Поместим двоичные данные внешней обработки во временное хранилище (обычно это делается при открытии формы или передается как параметр).
  2. Вызовем процедуру с директивой &НаСервереБезКонтекста, передав туда адрес хранилища и необходимые данные из формы в виде простой структуры.
  3. На сервере создадим экземпляр обработки из двоичных данных, заполним его свойства и вызовем нужный метод.

Посмотрим на пример реализации такого подхода:


&НаКлиенте
Процедура ВыполнитьДействиеБезКонтекста()
    
    // Подготавливаем данные, которые нужны для работы модуля объекта
    ПараметрыВызова = Новый Структура;
    ПараметрыВызова.Вставить("Контрагент", Объект.Контрагент);
    ПараметрыВызова.Вставить("Сумма", Объект.СуммаОперации);
    
    // АдресХранилища - это адрес, где лежат двоичные данные нашей обработки
    // Его можно получить при создании формы
    Результат = ВызватьМетодОбъектаНаСервере(АдресХранилища, ПараметрыВызова);
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ВызватьМетодОбъектаНаСервере(АдресХранилища, ПараметрыВызова)
    
    // Получаем объект обработки из хранилища
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
    ИмяФайла = ПолучитьИмяВременногоФайла("epf");
    ДвоичныеДанные.Записать(ИмяФайла);
    
    ВнешняяОбработка = ВнешниеОбработки.Создать(ИмяФайла, Ложь);
    
    // Заполняем данные объекта из переданной структуры
    ЗаполнитьЗначенияСвойств(ВнешняяОбработка, ПараметрыВызова);
    
    // Вызываем экспортный метод
    Результат = ВнешняяОбработка.РасчитатьДанные();
    
    УдалитьФайлы(ИмяФайла);
    Возврат Результат;
    
КонецФункции

Решение 2. Интеграция с БСП (Дополнительные отчеты и обработки)

Если ваша внешняя обработка подключена через подсистему БСП «Дополнительные отчеты и обработки», ситуация упрощается. Выясним причину: БСП уже хранит двоичные данные обработки в информационной базе. Мы можем использовать программный интерфейс БСП для получения объекта.

Рассмотрим по шагам, как это реализовать в неконтекстном вызове:


&НаСервереБезКонтекста
Процедура ВыполнитьЧерезБСП(СсылкаНаОбработку, ДанныеОбъекта)
    
    // Используем штатный метод БСП для получения экземпляра объекта
    // СсылкаНаОбработку - это ссылка на элемент справочника ДополнительныеОтчетыИОбработки
    ОбъектОбработки = ДополнительныеОтчетыИОбработки.ОбъектВнешнейОбработки(СсылкаНаОбработку);
    
    // Заполняем реквизиты объекта
    ЗаполнитьЗначенияСвойств(ОбъектОбработки, ДанныеОбъекта);
    
    // Вызываем нужную логику
    ОбъектОбработки.ВыполнитьКоманду();
    
КонецПроцедуры

Этот способ является наиболее изящным и безопасным, так как платформа сама заботится о создании объекта и компиляции его модуля в памяти сервера.

Решение 3. Передача «Объекта» формы в неконтекстный вызов

Существует интересный нюанс работы платформы 1С: если передать реквизит формы Объект (тип ДанныеФормыСтруктура) как параметр в процедуру &НаСервереБезКонтекста, то на сервер будет передан только этот реквизит, а не весь контекст формы (элементы управления, другие реквизиты и т.д.).

Проанализируем пример, предложенный участниками обсуждения:


&НаКлиенте
Процедура ВызовСМинимальнымКонтекстом()
    ВыполнитьНаСервереБезКонтекста(Объект);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВыполнитьНаСервереБезКонтекста(ДанныеФормы)
    
    // Для внешних обработок ДанныеФормыВЗначение требует типа
    // Поэтому сначала создаем пустой объект
    // Здесь ПутьКФайлу должен быть доступен серверу
    ОбъектЗначение = ВнешниеОбработки.Создать(ПутьКФайлу);
    
    // Синхронизируем данные из переданного параметра в созданный объект
    ДанныеФормыВЗначение(ДанныеФормы, ОбъектЗначение);
    
    // Теперь нам доступны все методы модуля объекта
    ОбъектЗначение.МояЭкспортнаяПроцедура();
    
КонецПроцедуры

Важный момент: использование ДанныеФормыВЗначение в данном случае позволяет избежать передачи «лишнего» контекста формы (например, динамических списков или тяжелых временных переменных формы), передавая только структуру самого объекта.

Проблема мутабельных значений и временного хранилища

Разберем ситуацию, упомянутую в обсуждении: почему нельзя просто положить ОбработкаОбъект во временное хранилище и доставать его оттуда? Выясним причину: объекты типа СправочникОбъект, ДокументОбъект и ВнешняяОбработкаОбъект являются мутабельными. Платформа запрещает их передачу между клиентом и сервером (через границы вызовов) и не позволяет помещать их напрямую во временное хранилище.

Попытка выполнить код ПоместитьВоВременноеХранилище(ЭтотОбъект) приведет к ошибке. Поэтому мы всегда вынуждены либо передавать данные (структуру), либо воссоздавать объект из двоичных данных (файла .epf).

Архитектурные рекомендации

Проанализировав проблему, можно прийти к выводу, что сама необходимость вызывать модуль объекта с клиента без контекста часто сигнализирует о нарушении архитектуры. Рассмотрим правильный подход:

  1. Разделение логики: Выносите алгоритмы, которые должны работать и из формы, и по расписанию (регламентно), в общие модули или в программный интерфейс БСП.
  2. Метод-обертка: В модуле объекта создавайте методы, которые принимают на вход не свойства ЭтотОбъект, а структуру параметров. Это позволит легко вызывать их из любого места программы.
  3. Минимизация данных формы: Если контекст формы слишком тяжелый, проанализируйте, все ли данные должны быть реквизитами формы. Возможно, часть данных стоит хранить во временном хранилище и подгружать только при необходимости.

Подводя итог, можно сказать, что вызвать модуль объекта без контекста реально, но это требует либо наличия ссылки на внешнюю обработку (через БСП), либо возможности создать объект заново на сервере из файла с последующим заполнением его данными из формы.

← На главную