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