Как передать значение ОбъектXDTO с сервера на клиент в 1С:Предприятие 8.3?

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

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

Попытки обойти эту проблему с помощью стандартных механизмов платформы, таких как ПоместитьВоВременноеХранилище, ПолучитьИзВременногоХранилища или ЗначениеВСтрокуВнутрь, также не приводят к успеху: при выгрузке возвращается значение Неопределено. Разберем детально, почему это происходит и как правильно передать данные XDTO на сторону клиента.

Выясним причину ошибки

Проанализируем архитектурное ограничение платформы 1С:Предприятие. Несмотря на то, что объектный тип ОбъектXDTO формально доступен в синтакс-помощнике и на сервере, и на тонком клиенте, он не поддерживает внутреннюю сквозную сериализацию платформы, используемую для клиент-серверного взаимодействия (RPC-вызовов).

Механизмы временного хранилища и функция ЗначениеВСтрокуВнутрь используют точно такой же базовый транспортный формат сериализации. Если платформа встречает неподдерживаемый тип, она либо выбрасывает исключение отображения типов, либо заменяет значение на Неопределено. Следовательно, передать напрямую экземпляр типа ОбъектXDTO через параметры или возвращаемое значение функции нельзя.

Для корректной передачи данных необходимо преобразовать объект в промежуточный формат, поддерживающий клиент-серверный обмен (например, в строку XML), либо десериализовать данные в универсальную структуру на сервере.

Способ 1. Сериализация в XML-строку через ФабрикаXDTO

Рассмотрим основной способ решения, когда на клиенте действительно требуется восстановить исходный объект XDTO. В этом случае на сервере объект сериализуется в строку XML, строка возвращается на клиент, а на клиенте восстанавливается обратно в ОбъектXDTO.

При использовании этого способа важно избегать частых ошибок:

  1. Нельзя использовать СериализаторXDTO для произвольных объектов XDTO, так как он предназначен для сериализации прикладных объектов 1С (справочников, документов, наборов записей), а не самих данных модели XDTO. Для объектов XDTO необходимо использовать объект ФабрикаXDTO.
  2. Перед записью в объект ЗаписьXML необходимо обязательно инициализировать строковый буфер методом УстановитьСтроку(), иначе возникнет ошибка «Не установлен приемник XML».
  3. Для получения результирующей строки необходимо корректно закрыть поток методом Закрыть().

Посмотрим на пример кода, выполняемого на стороне сервера:


&НаСервере
Функция ПолучитьДанныеXDTOНаСервере()
    
    // Получаем или формируем исходный объект XDTO
    ОбъектДанныхXDTO = ПолучитьОбъектXDTO(); 
    
    // Создаем объект записи XML и инициализируем строку
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку();
    
    // Выполняем запись объекта в XML через фабрику
    ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ОбъектДанныхXDTO);
    
    // Получаем итоговую строку XML
    СтрокаXML = ЗаписьXML.Закрыть();
    
    Возврат СтрокаXML;
    
КонецФункции

Теперь разберем, как восстановить объект на стороне тонкого клиента:


&НаКлиенте
Процедура ОбработатьДанныеНаКлиенте()
    
    // Получаем данные с сервера в виде сериализованной строки
    СтрокаXML = ПолучитьДанныеXDTOНаСервере();
    
    Если ПустаяСтрока(СтрокаXML) Тогда
        Возврат;
    КонецЕсли;
    
    // Инициализируем чтение XML
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXML);
    
    // Считываем объект XDTO обратно
    ВосстановленныйОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
    ЧтениеXML.Закрыть();
    
    // Далее работаем с объектом XDTO на клиенте
    
КонецПроцедуры

Важное замечание о фабриках: Глобальный контекст ФабрикаXDTO содержит описание только тех типов, которые объявлены в ветке метаданных конфигурации «Общие — XDTO-пакеты» или предопределены платформой. Если объект был создан сторонней фабрикой (например, получен из WS-ссылки внешнего веб-сервиса), десериализация через глобальную ФабрикаXDTO на клиенте выдаст ошибку неизвестного типа. В этом случае чтение должно выполняться фабрикой, содержащей соответствующую схему (например, WSСсылки[ИмяСсылки].ПолучитьWSОпределения().ФабрикаXDTO).

Способ 2. Использование функций Библиотеки стандартных подсистем (БСП)

Если конфигурация разработана на базе Библиотеки стандартных подсистем, мы можем не писать низкоуровневую работу с объектами ЗаписьXML и ЧтениеXML вручную. В БСП предусмотрены готовые проверенные методы в общем модуле ОбщегоНазначения.

Посмотрим на реализацию с использованием БСП:


// На стороне сервера формируем строку:
СтрокаXML = ОбщегоНазначения.ОбъектXDTOВСтрокуXML(ОбъектДанныхXDTO);

// На стороне клиента восстанавливаем объект:
ВосстановленныйОбъектXDTO = ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(СтрокаXML);

Эти функции внутри себя самостоятельно создают потоки чтения и записи XML, корректно закрывают дескрипторы и поддерживают передачу пользовательской фабрики в качестве второго параметра, если типы не входят в состав глобальной фабрики.

Способ 3. Преобразование данных в прикладные структуры (рекомендуемый подход)

Проанализируем стандарты разработки 1С. Передача сырых XML-данных или объектов XDTO на тонкий клиент считается неоптимальной практикой. Клиентский уровень предназначен для отображения пользовательского интерфейса и базовой интерактивной логики, а не для тяжелого парсинга схем данных.

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

Разберем по шагам серверный разбор данных:


&НаСервере
Функция ПолучитьДанныеДляФормы()
    
    ИсходныйОбъект = ПолучитьОбъектXDTO();
    
    Результат = Новый Структура;
    Результат.Вставить("Идентификатор", ИсходныйОбъект.Id);
    Результат.Вставить("Наименование", ИсходныйОбъект.Name);
    Результат.Вставить("Сумма", ИсходныйОбъект.Amount);
    
    // Структура без проблем передается на тонкий клиент
    Возврат Результат;
    
КонецФункции

Такой подход обеспечивает наилучшую производительность клиентского приложения, экономит сетевой трафик и защищает код клиентской части от усложнения логикой обработки XML.

← На главную