Как вызывать ЗаписатьJSON в веб-сервисе расширения, если нельзя указать модуль преобразования?

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

При разработке веб-сервисов и HTTP-сервисов в расширениях конфигурации разработчики часто сталкиваются с необходимостью выгрузки данных в формат JSON. Если структуры данных содержат сложные типы (например, таблицы значений, ссылки на справочники, документы или неопределенные значения), встроенный метод 1С ЗаписатьJSON требует указания обработчика сложного типа — экспортной функции в параметре ИмяФункцииПреобразования и соответствующего модуля в параметре МодульПреобразования.

Однако в контексте веб-сервиса расширения возникают архитектурные ограничения платформы 1С. Разберем подробнее, почему возникает эта проблема и какими способами ее можно решить.

Почему возникает ошибка при вызове ЗаписатьJSON

Выясним главные причины, по которым штатный вызов функции преобразования вызывает ошибку:

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

Проанализируем практические варианты обхода данного ограничения.

Вариант 1. Предварительное приведение данных к примитивным типам

Наиболее простое и надежное решение — отказаться от использования параметра ИмяФункцииПреобразования и подготовить структуру данных заранее перед вызовом сериализатора. Для этого все сложные типы приводятся к базовым типам 1С (массивы, структуры, строки, числа, булево).

Рассмотрим пример обхода таблицы значений и приведения ссылок к строковому представлению:


Функция ПреобразоватьТаблицуВМассив(ТаблицаЗначений)
    МассивРезультат = Новый Массив;
    
    Для Каждого Стр Из ТаблицаЗначений Цикл
        ЭлементСтруктура = Новый Структура;
        Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
            Значение = Стр[Колонка.Имя];
            
            // Обработка ссылочных типов и сложных значений
            Если ЗначениеЗаполнено(Значение) Тогда
                Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
                    ЭлементСтруктура.Вставить(Колонка.Имя, Строка(Значение));
                ИначеЕсли Справочники.ТипВсехСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
                    ЭлементСтруктура.Вставить(Колонка.Имя, Строка(Значение));
                Иначе
                    ЭлементСтруктура.Вставить(Колонка.Имя, Значение);
                КонецЕсли;
            Иначе
                ЭлементСтруктура.Вставить(Колонка.Имя, "");
            КонецЕсли;
        КонецЦикла;
        МассивРезультат.Добавить(ЭлементСтруктура);
    КонецЦикла;
    
    Возвращать МассивРезультат;
КонецФункции

После такой подготовки вызов метода ЗаписатьJSON выполняется без указания модуля преобразования:


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПодготовленныйМассив);
СтрокаJSON = ЗаписьJSON.Закрыть();

Вариант 2. Использование внешней обработки в качестве модуля

Тип ВнешняяОбработкаОбъект является допустимым значением для параметра МодульПреобразования. Мы можем хранить файл внешней обработки в макете расширения (как двоичные данные) или во временном каталоге, подключать его в коде сервиса и передавать экземпляр обработки в метод ЗаписатьJSON.

Разберем пример реализации по шагам:

  1. В внешней обработке создаем экспортную функцию преобразования, например ОбработкаСложныхТипов(Свойства, Отказ).
  2. В коде веб-сервиса сохраняем внешнюю обработку из макета во временный файл и подключаем ее:
    
    ИмяФайла = ПолучитьИмяВременногоФайла("epf");
    ДвоичныеДанные = ПолучитьМакет("ВнешняяОбработкаПреобразованияJSON");
    ДвоичныеДанные.Записать(ИмяФайла);
    
    ОбработкаОбъект = ВнешниеОбработки.Создать(ИмяФайла);
    ЗаписатьJSON(ЗаписьJSON, МассивJSON, , "ОбработкаСложныхТипов", ОбработкаОбъект);
    
    УдалитьФайлы(ИмяФайла);
    

Вариант 3. Использование существующих общих модулей основной конфигурации

Если в основной конфигурации уже есть серверный общий модуль с универсальными функциями преобразования (например, модули БСП ОбщегоНазначенияКлиентСервер или модули работы с JSON), расширение может свободно использовать их имя в качестве параметра МодульПреобразования.

Посмотрим на пример передачи имени существующего модуля:

ЗаписатьJSON(ЗаписьJSON, Данные, , "ОбработкаСложныхТипов", ОбщийМодульИмя);

Вариант 4. Сериализация через СериализаторXDTO

Если приемник JSON готов принимать данные в формате XDTO 1С, вместо ручного обхода и вызова ЗаписатьJSON можно воспользоваться вызовом СериализаторXDTO. Он умеет автоматически раскладывать ссылочные типы, таблицы значений и наборы записей без необходимости передавать модуль преобразования:


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ДанныеОбъект, НазначениеТипаXML.Явное);
СтрокаJSON = ЗаписьJSON.Закрыть();

Важно: Данный способ формирует специфическую структуру JSON с тегами типов 1С, поэтому его стоит применять в случаях, когда на принимающей стороне также используется платформа 1С или имеется парсер формата 1С XDTO.

← На главную