При разработке интеграций через Web-сервисы программисты часто сталкиваются с ситуацией, когда простые типы данных (строки, числа) передаются без проблем, но попытка вернуть ХранилищеЗначений, содержащее ТаблицуЗначений, заканчивается ошибкой или получением пустого результата на стороне приемника. Давайте вместе разберем, почему это происходит, и проанализируем наиболее эффективные способы решения этой задачи.
Разберем ситуацию: тип ValueStorage (соответствующий ХранилищеЗначений в 1С) описан в стандартном пространстве имен http://v8.1c.ru/8.1/data/core. Казалось бы, платформа должна автоматически сериализовать его в XML и передать. Однако ХранилищеЗначений — это не просто контейнер, а специфический объект, который может содержать внутри себя практически любые данные 1С.
Проблема кроется в XDTO-сериализации. Когда мы помещаем в хранилище ТаблицуЗначений, платформа пытается превратить её в XML-структуру. Если в этой таблице содержатся «сложные» типы данных (ссылки на справочники, документы, специфические перечисления или другие объекты, не описанные в XDTO-пакете сервиса), процесс сериализации либо обрывается, либо формирует некорректный пакет данных. Выясним причину: приемник просто «не знает», как интерпретировать внутренние ссылки 1С, которые имеют смысл только внутри исходной базы.
Рассмотрим первый способ, который позволяет использовать штатные механизмы 1С. Чтобы ТаблицаЗначений успешно прошла через Web-сервис внутри ХранилищаЗначений, мы должны гарантировать, что все данные в ней являются примитивными типами (строка, число, булево, дата).
Проанализируем пример кода на стороне сервера (Web-сервиса):
// Получаем данные
Результат = Запрос.Выполнить().Выгрузить();
// Подготовка: преобразуем все ссылочные типы в строки (UUID или Коды)
Для Каждого СтрокаТЗ Из Результат Цикл
// Например, заменяем ссылку на Контрагента его строковым представлением
СтрокаТЗ.Контрагент = Строка(СтрокаТЗ.Контрагент.УникальныйИдентификатор());
КонецЦикла;
// Создаем хранилище
ХранЗн = Новый ХранилищеЗначений(Результат);
Возврат ХранЗн;
Важный момент: на стороне приемника вы должны выполнить обратное преобразование, если вам снова нужны ссылки. Это требует, чтобы база-приемник имела аналогичные данные или могла идентифицировать объекты по переданным идентификаторам. После завершения миграции рекомендуется выполнить автоматическую сверку проводок между базами 1С для поиска возможных расхождений.
Если нам нужно передать данные «как есть», не полагаясь на автоматическую XML-сериализацию типов 1С, мы можем использовать преобразование в Base64. Этот метод превращает двоичные данные хранилища в обычную строку, которую Web-сервис передаст гарантированно.
Разберем по шагам алгоритм реализации этого метода:
1. На стороне сервера (в методе Web-сервиса):
ХранилищеЗначений с нашей таблицей.ДвоичныеДанные.string или base64Binary).
Функция ПолучитьДанныеВBase64()
Результат = Запрос.Выполнить().Выгрузить();
ХранЗн = Новый ХранилищеЗначений(Результат);
// Получаем двоичные данные из хранилища
ДвоичныеДанные = ХранЗн.Получить();
// Преобразуем в строку для безопасной передачи
Возврат Base64Строка(ДвоичныеДанные);
КонецФункции
2. На стороне клиента (приемника):
ДвоичныеДанные.ХранилищеЗначений из этих данных.ТаблицуЗначений методом Получить().
СтрокаBase64 = Прокси.ПолучитьДанныеВBase64();
ДвоичныеДанные = Base64Данные(СтрокаBase64);
ХранЗн = Новый ХранилищеЗначений(ДвоичныеДанные);
ТЗ = ХранЗн.Получить();
Этот способ позволяет избежать любых проблем с XSD-схемами и типами данных, так как для Web-сервера это выглядит как передача обычного текста. При необходимости уменьшить размер передаваемой строки можно использовать методы сжатия строковых данных в Base64 средствами 1С.
Рассмотрим ситуацию, когда нам нужно передать сложную структуру, но мы хотим остаться в рамках типизации 1С. Мы можем принудительно сериализовать объект в XML-строку перед помещением в хранилище. Посмотрим на пример:
// Сериализация ТЗ в XML-строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТаблицаЗначений);
XMLСтрокаДанных = ЗаписьXML.Закрыть();
// Помещаем XML-строку в хранилище
ХранЗн = Новый ХранилищеЗначений(XMLСтрокаДанных);
Возврат ХранЗн;
Преимущество этого метода в том, что СериализаторXDTO лучше справляется с преобразованием стандартных типов 1С, чем автоматический механизм Web-сервиса при передаче объекта «напрямую».
Если ваша ТаблицаЗначений содержит тысячи строк, передача через XML может быть медленной. Проанализируем способы ускорения процесса:
ХранилищеЗначений используйте конструктор с указанием степени сжатия: Новый ХранилищеЗначений(Данные, Новый СжатиеДанных(9)). Это значительно уменьшит размер передаваемого пакета.FastInfoset. Это бинарный формат оптимизации XML, который ускоряет работу с большими объемами данных.С точки зрения архитектуры, использование ХранилищеЗначений — это «черный ящик», который понятен только системе на базе 1С. Если вы планируете, что ваш Web-сервис будет вызываться сторонними приложениями (на Java, C#, Python), они не смогут просто так извлечь данные из ValueStorage.
В таких случаях рекомендуется создать в конфигурации собственный XDTO-пакет, который описывает структуру вашей таблицы (строки и колонки). Тогда Web-сервис будет возвращать типизированный объект, который любая внешняя система сможет легко распарсить. Это более трудоемкий, но наиболее правильный путь для построения надежных API. Если же стандартная интеграция невозможна, можно использовать программных роботов для переноса данных через визуальный интерфейс программ.
Подведем итог: если вы работаете в связке 1С-1С и вам нужно быстро передать ТЗ, используйте метод с Base64 — он избавит вас от большинства ошибок сериализации. Если же важна совместимость с внешним миром — проектируйте XDTO-структуру. Кроме того, вы можете настроить регулярный обмен данными через веб-сервисы в автоматическом режиме по заданному расписанию.