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