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