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