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