При разработке функционала выгрузки печатных форм или отчетов часто возникает задача: сформировать на сервере пачку документов и передать их на сторону клиента. Разработчики нередко пытаются вызвать метод ПоместитьВоВременноеХранилище внутри цикла, а затем последовательно забирать файлы на клиенте. Однако на практике оказывается, что клиентский код успешно получает только первый документ, а при попытке получить остальные платформа выдает пустое значение или ошибку. Разберем по шагам, почему так происходит и как правильно организовать передачу нескольких объектов.
Посмотрим на синтаксис метода платформы: ПоместитьВоВременноеХранилище(<Данные>, <Адрес>). Второй параметр является необязательным, и именно в нем кроется причина проблемы.
Выясним причину такого поведения платформы:
Адрес = ПоместитьВоВременноеХранилище(...) без сохранения ссылок в массив.Если нам необходимо получить адреса для каждого документа по отдельности, следует явно указать владельца хранилища — УникальныйИдентификатор управляемой формы. В этом случае данные будут существовать на сервере вплоть до момента закрытия формы пользователем.
Рассмотрим пример формирования документов на сервере с сохранением ссылок в массив:
&НаСервере
Функция СформироватьТабличныеДокументыНаСервере()
МассивАдресов = Новый Массив;
Для Счетчик = 1 По 5 Цикл
ТабДок = Новый ТабличныйДокумент;
// Заполняем документ данными
// Передаем УникальныйИдентификатор текущей формы вторым параметром
АдресФайла = ПоместитьВоВременноеХранилище(ТабДок, ЭтаФорма.УникальныйИдентификатор);
МассивАдресов.Добавить(АдресФайла);
КонецЦикла;
Возврат МассивАдресов;
КонецФункции
Теперь на клиенте можно безопасно обходить массив адресов. Даже если получение данных сопровождается вызовами сервера, платформа не удалит значения до закрытия окна формы.
Вместо многократного помещения отдельных объектов во временное хранилище гораздо эффективнее собрать все сформированные документы в единый контейнер — Массив или Структура — и поместить во временное хранилище только один объект.
Посмотрим на пример реализации:
&НаСервере
Функция ПоместитьВсеДокументыВХранилище()
СписокДокументов = Новый Массив;
Для Индекс = 1 По 3 Цикл
ТабДок = Новый ТабличныйДокумент;
// Формирование содержимого
СписокДокументов.Добавить(ТабДок);
КонецЦикла;
// Помещаем весь массив за один вызов
Возврат ПоместитьВоВременноеХранилище(СписокДокументов, ЭтаФорма.УникальныйИдентификатор);
КонецФункции
&НаКлиенте
Процедура ПолучитьДокументы()
АдресХранилища = ПоместитьВсеДокументыВХранилище();
// Извлекаем массив со всеми табличными документами
МассивДокументов = ПолучитьИзВременногоХранилища(АдресХранилища);
Для Каждого ТекТабДок Из МассивДокументов Цикл
// Работаем с каждым табличным документом на клиенте
ТекТабДок.Показать();
КонецЦикла;
КонецПроцедуры
Такой подход избавляет от необходимости генерировать множество адресов и уменьшает накладные расходы на обращение к временному хранилищу.
Проанализируем особенности объекта ТабличныйДокумент в платформе 1С:Предприятие 8.3: данный тип данных является сериализуемым и может передаваться между клиентом и сервером напрямую без использования временного хранилища, если процедура не выполняется в фоновом задании.
Разберем компактный вариант передачи без промежуточных адресов:
&НаСервереБезКонтекста
Функция ПолучитьМассивПечатныхФорм()
Результат = Новый Массив;
Для Каждого Элемент Из СписокОбъектов Цикл
ТабДок = Новый ТабличныйДокумент;
// Заполнение макета
Результат.Добавить(ТабДок);
КонецЦикла;
Возврат Результат;
КонецФункции
Если конечной целью является сохранение документов на диск клиента (например, в форматах PDF или Excel), наиболее производительным решением будет пакетная передача двоичных данных.
Разберем по шагам алгоритм пакетного сохранения:
ТабличныйДокумент во временный файл нужного формата.ДвоичныеДанные.ОписаниеПередаваемогоФайла и вызываем асинхронную процедуру НачатьПолучениеФайлов. Это позволяет сохранить все файлы на диск за одну операцию без вывода множества диалоговых окон пользователю.Обратим внимание на управление ресурсами сервера при работе с временным хранилищем:
Новый УникальныйИдентификатор вместо идентификатора формы, данные останутся в памяти рабочего процесса rphost до завершения сеанса пользователя. Чтобы не перегружать оперативную память сервера большими табличными документами, вызывайте УдалитьИзВременногоХранилища(Адрес) сразу после того, как данные прочитаны на клиенте.