Какие значения переживут серверный вызов в управляемой форме 1С 8.3

· 9 мин

Содержание

С сервера на клиент в 1С 8.3 передаются только значения, тип которых одновременно доступен на клиенте и сериализуется: примитивы (Число, Строка, Дата, Булево, Неопределено, Null), ссылки, УникальныйИдентификатор, Массив, Структура, Соответствие, СписокЗначений, ДвоичныеДанные, ТабличныйДокумент и данные формы. ТаблицаЗначений, ДеревоЗначений, Запрос, РезультатЗапроса, объекты справочников и документов, наборы записей и объекты метаданных на клиент не попадут.

Типичная ситуация: функция с &НаСервере возвращает выгрузку запроса, а клиент получает ошибку вызова. Лечится это не настройкой, а сменой типа: таблицу превращают в массив структур или в реквизит формы, объект — в данные формы, метаданные — в строку.

Общее правило передачи данных между сервером и клиентом

Любой серверный вызов из клиентского кода — это сериализация. Платформа упаковывает параметры, отправляет их на сервер, выполняет метод и упаковывает обратно результат. Если хотя бы одно значение внутри не упаковывается, падает весь вызов.

Тип годится для передачи, если выполняются два условия:

  • ✅ в Синтакс-помощнике в разделе «Доступность» у типа указан тонкий клиент (и веб-клиент, если он у вас используется);
  • ✅ тип сериализуемый — то есть его можно записать в XML и прочитать обратно.

Правило работает рекурсивно. Массив передаётся, но массив, в котором лежит ТаблицаЗначений, — уже нет. То же со Структурой и Соответствием: проверяется каждое вложенное значение.

Передача идёт в трёх местах:

  1. Параметры и возвращаемое значение методов с директивами &НаСервере и &НаСервереБезКонтекста, вызванных с клиента.
  2. Реквизиты формы — при вызове &НаСервере они уходят на сервер и возвращаются целиком.
  3. Параметры открываемой формы (ОткрытьФорму со структурой параметров) и общие модули с признаком «Вызов сервера».

&НаСервереБезКонтекста не тащит на сервер реквизиты формы. Если методу нужна только ссылка и пара чисел, эта директива в разы легче по трафику, чем &НаСервере.

Примитивные типы, строки и даты

Простые значения проходят без оговорок:

ТипПример значенияЗамечание
Число150.25точность сохраняется
Строка"ИНН 7701234567"длинные строки тоже, но это трафик
Дата'20260107000000'время передаётся вместе с датой
БулевоИстина—
НеопределеноНеопределеноудобно как «нет результата»
NullNullприходит из запросов; на клиенте сравнивайте через = Null

Строка — самый частый способ протащить на клиент то, что иначе не проходит. Например, полное имя объекта метаданных или адрес во временном хранилище: оба значения — обычные строки.

Строки в сотни килобайт (сериализованные XML, JSON, Base64) гоняются при каждом вызове туда и обратно, если параметр объявлен без Знач. Такие данные кладите во временное хранилище, а на клиент отдавайте адрес.

Ссылки, перечисления и уникальные идентификаторы

Ссылочные значения передаются полностью: СправочникСсылка.*, ДокументСсылка.*, ПеречислениеСсылка.*, ПланВидовХарактеристикСсылка.*, ПланСчетовСсылка.*, ПланОбменаСсылка.*, БизнесПроцессСсылка.*, ЗадачаСсылка.*. Сюда же относятся ключи записей регистров и УникальныйИдентификатор.

Подвох в другом. Ссылка на клиенте — это только идентификатор плюс представление. Прочитать через точку реквизит объекта (Объект.Контрагент.ИНН) в клиентском коде нельзя: в тонком клиенте нет доступа к базе. Реквизит получают серверной функцией:

&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
	ИНН = ИННКонтрагента(Объект.Контрагент);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ИННКонтрагента(Знач Контрагент)
	Возврат Контрагент.ИНН;
КонецФункции

В конфигурациях на БСП вместо своей функции обычно берут ОбщегоНазначения.ЗначениеРеквизитаОбъекта или ЗначенияРеквизитовОбъекта — последняя возвращает Структуру сразу с несколькими полями за один вызов.

С перечислениями своя история. Менеджер Перечисления.ВидыОперацийПоступление на клиенте недоступен, а вот само значение перечисления — доступно. Для сравнения в клиентском коде используйте ПредопределенноеЗначение:

&НаКлиенте
Процедура ОбновитьВидимость()
	ЭтоТовары = (Объект.ВидОперации =
		ПредопределенноеЗначение("Перечисление.ВидыОперацийПоступление.Товары"));
	Элементы.Склад.Видимость = ЭтоТовары;
КонецПроцедуры

Имя перечисления в примере условное — подставьте своё. Так же работает с предопределёнными элементами справочников и планов счетов.

Массивы, структуры и соответствия на клиенте

Универсальные коллекции — основной транспорт между контекстами:

  • 📦 Массив и ФиксированныйМассив;
  • 📦 Структура и ФиксированнаяСтруктура;
  • 📦 Соответствие и ФиксированноеСоответствие;
  • 📦 СписокЗначений — с пометками, картинками и представлениями.

Ключ Структуры — строка по правилам имени переменной. Ключом Соответствия может быть любое передаваемое значение, например ссылка на номенклатуру. Это удобно, когда клиенту нужна справочная таблица «товар → цена».

Фиксированные варианты полезны, когда коллекция лежит в параметрах формы или кэшируется в модуле с повторным использованием возвращаемых значений: случайно изменить её не получится.

Если параметр серверного метода объявлен без Знач, платформа после вызова возвращает его значение на клиент. Для массива на 10 000 элементов это лишний рейс в обратную сторону. Ставьте Знач, если метод не должен менять параметр.

Пример: вернуть несколько значений одним вызовом

&НаСервереБезКонтекста
Функция ДанныеДляШапки(Знач Документ)
	Результат = Новый Структура;
	Результат.Вставить("Сумма", Документ.СуммаДокумента);
	Результат.Вставить("Контрагент", Документ.Контрагент);
	Результат.Вставить("Проведен", Документ.Проведен);
	Возврат Результат;
КонецФункции

Один вызов вместо трёх. На медленном канале разница видна сразу.

Таблица значений и наборы записей: как передать на клиент

ТаблицаЗначений и ДеревоЗначений на клиенте не существуют. Возврат выгрузки запроса из серверной функции, вызванной с клиента, заканчивается ошибкой. Наборы записей регистров (РегистрСведенийНаборЗаписей и другие) тоже живут только на сервере.

Есть три рабочих способа.

Способ 1. Реквизит формы

Создайте реквизит формы типа ТаблицаЗначений с нужными колонками. На клиенте он виден как ДанныеФормыКоллекция — по нему можно идти циклом, искать строки, выводить в таблицу на форме. Заполняют его на сервере:

&НаСервере
Процедура ЗаполнитьТоварыНаСервере()
	Таблица = ПолучитьТаблицуТоваров(); // любая ТаблицаЗначений
	ЗначениеВРеквизитФормы(Таблица, "ТаблицаТоваров");
КонецПроцедуры

Обратное преобразование — РеквизитФормыВЗначение("ТаблицаТоваров"). Для табличной части объекта подойдёт Объект.Товары.Загрузить(Таблица).

Способ 2. Массив структур

Когда таблица нужна в общем клиентском модуле, а не в форме, её раскладывают на массив структур:

&НаСервереБезКонтекста
Функция ОстаткиДляКлиента(Знач Склад)
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Остатки.Номенклатура КАК Номенклатура,
	|	Остатки.КоличествоОстаток КАК Количество
	|ИЗ
	|	РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки";
	Запрос.УстановитьПараметр("Склад", Склад);
	Таблица = Запрос.Выполнить().Выгрузить();

	Результат = Новый Массив;
	Для Каждого СтрокаТаблицы Из Таблица Цикл
		Результат.Добавить(Новый Структура("Номенклатура, Количество",
			СтрокаТаблицы.Номенклатура, СтрокаТаблицы.Количество));
	КонецЦикла;
	Возврат Результат;
КонецФункции

Имя регистра условное. В БСП то же самое делает ОбщегоНазначения.ТаблицаЗначенийВМассив.

Способ 3. Не передавать вовсе

Часто клиенту не нужна вся таблица — нужна сумма, флаг «есть остатки» или первые пять строк. Посчитайте это на сервере и верните число или булево значение. Самый быстрый вызов — тот, в котором мало данных.

СпособКогда выбиратьМинусы
Реквизит формыданные показываются на формеходит туда и обратно при каждом &НаСервере
Массив структурданные нужны в клиентском модулеручная раскладка колонок
Итог на сервереклиенту нужен вывод, а не строкине подходит для интерактивной работы со строками

Двоичные данные, табличный документ, типы и метаданные

Помимо коллекций, на клиент проходят специализированные типы:

  • 🗂 ДвоичныеДанные — файлы, картинки, вложения;
  • 🗂 ХранилищеЗначения — передаётся, но распаковать его методом Получить() можно только на сервере;
  • 🗂 ТабличныйДокумент и ТекстовыйДокумент — именно так печатные формы попадают на экран;
  • 🗂 Тип и ОписаниеТипов — проверка ТипЗнч(Значение) = Тип("ДокументСсылка.РеализацияТоваровУслуг") работает и на клиенте;
  • 🗂 Цвет, Шрифт, Картинка, ФорматированнаяСтрока — для оформления.

С двоичными данными объёмом в мегабайты лучше работать через временное хранилище. Сервер кладёт данные и возвращает адрес-строку:

&НаСервере
Функция АдресФайлаНаСервере()
	Данные = СформироватьВыгрузку(); // возвращает ДвоичныеДанные
	Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции

На клиенте адрес передают в метод получения файла или в ПолучитьИзВременногоХранилища. Второй аргумент — уникальный идентификатор формы: хранилище очистится, когда форму закроют.

Объекты метаданных на клиенте недоступны: Метаданные.Документы.Поступление в клиентском коде не сработает. Передавайте строку ПолноеИмя() или синоним, а свойства метаданных читайте на сервере и возвращайте структурой.

Например, клиенту нужно знать, есть ли у документа табличная часть «Услуги». Серверная функция проверяет это по метаданным и возвращает Булево. Если таких проверок много и результат не меняется в течение сеанса, вынесите функцию в общий модуль с повторным использованием возвращаемых значений: повторный вызов с теми же параметрами не пойдёт на сервер.

Данные формы и параметры открываемой формы

Реквизиты управляемой формы на клиенте представлены особыми типами — данными формы. Их платформа передаёт сама, и именно через них клиент работает с объектами и таблицами:

Тип реквизита на сервереЧто видит клиентКак преобразовать на сервере
ДокументОбъект.Х, СправочникОбъект.ХДанныеФормыСтруктураДанныеФормыВЗначение, ЗначениеВДанныеФормы
ТаблицаЗначений, табличная частьДанныеФормыКоллекцияРеквизитФормыВЗначение, ЗначениеВРеквизитФормы
ДеревоЗначенийДанныеФормыДеревоте же методы формы
ДинамическийСписокстроки списка по ключамданные читаются запросом на сервере

Данные формы можно передать параметром в серверную процедуру, даже в &НаСервереБезКонтекста. Например, отправить на сервер только табличную часть Объект.Товары, а не всю форму целиком.

У динамического списка на клиенте доступна текущая строка: Элементы.Список.ТекущиеДанные возвращает поля, которые выведены в колонки. Если нужного поля в колонках нет, его добавляют в список (можно скрытой колонкой) или читают серверной функцией по ссылке.

Параметры ОткрытьФорму

Параметры открываемой формы — это Структура, и на её содержимое действуют те же ограничения. Ссылку, массив ссылок, число или строку передать можно. Таблицу значений или объект — нельзя: форма откроется с ошибкой.

&НаКлиенте
Процедура ОткрытьПодбор(Команда)
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("Склад", Объект.Склад);
	ПараметрыФормы.Вставить("АдресТоваров", ПоместитьТоварыВХранилище());
	ОткрытьФорму("Обработка.ПодборТоваров.Форма", ПараметрыФормы, ЭтотОбъект);
КонецПроцедуры

Имя обработки и функции условные. Приём с адресом временного хранилища здесь стандартный: открываемая форма в ПриСозданииНаСервере достаёт таблицу из хранилища и раскладывает её в свой реквизит. Сама таблица на клиенте не появляется ни разу.

Возврат значений из открытой формы через Закрыть(Результат) и обработчик ОписаниеОповещения подчиняется тем же правилам: результатом может быть массив ссылок или структура, но не таблица значений.

Какие типы нельзя передать с сервера на клиент

Эти типы чаще всего приводят к ошибке при вызове сервера:

ТипПочему не проходитЧем заменить
ТаблицаЗначений, ДеревоЗначенийнет на клиентереквизит формы, массив структур
Запрос, РезультатЗапроса, выборкаработает с базойвыгрузка → массив
СправочникОбъект, ДокументОбъектсерверный объектреквизит формы Объект, ДанныеФормыВЗначение на сервере
Справочники.Х, Документы.Х (менеджеры)серверныевызов серверной функции
наборы записей регистровсерверныемассив структур
МенеджерВременныхТаблицживёт в сеансе серверадержите на сервере, запрос выполняйте целиком там
ОбъектМетаданныхнет на клиентеПолноеИмя() строкой
СхемаКомпоновкиДанныхсервернаяадрес во временном хранилище
ОбъектXDTO, СериализаторXDTOсерверныестрока XML/JSON
форма (ЭтаФорма)не сериализуетсяпередайте нужные реквизиты

Объект документа нельзя вернуть на клиент даже «на минутку», чтобы поменять поле и записать. Правильная схема: форма объекта хранит его в реквизите Объект, правка идёт через данные формы, а запись — на сервере через ДанныеФормыВЗначение или РеквизитФормыВЗначение("Объект").

Обратное направление подчиняется тем же правилам. Передать с клиента на сервер ОписаниеОповещения с модулем формы или саму форму не получится, а ДанныеФормыКоллекция или Структуру — можно.

Как найти, какое значение ломает вызов

  1. Откройте отладчик и остановитесь на строке Возврат серверной функции.
  2. Посмотрите тип возвращаемого значения в табло, раскройте вложенные элементы коллекции.
  3. Найдите тип, у которого в Синтакс-помощнике нет клиентской доступности.
  4. Замените его по таблице выше и повторите вызов.

Если в структуре десятки ключей, поиск ускоряет временная проверка в цикле: на сервере пройдите по ключам и выведите ТипЗнч каждого значения через Сообщить.

Проверьте себя
Можно ли вернуть на клиент Структуру, в которой лежит ТаблицаЗначений?
Как сравнить реквизит формы со значением перечисления в клиентском коде?
Какая директива не передаёт на сервер реквизиты формы?

Частые вопросы

Почему в толстом клиенте код работал, а в тонком падает?
Толстый клиент в обычном приложении имеет доступ к базе и серверным типам. Тонкий и веб-клиент — нет, поэтому ТаблицаЗначений и чтение реквизитов через точку там недоступны.
Можно ли передать на клиент выборку из запроса, если она маленькая?
Нет. Размер не важен, важен тип. Выгрузите результат в таблицу и разложите в массив структур.
Передаётся ли ХранилищеЗначения?
Да, как значение передаётся. Но извлечь содержимое методом Получить() получится только на сервере.
Как посмотреть, сколько вызовов сервера делает форма?
В параметрах клиента включите отображение количества вызовов сервера или снимите замер производительности в отладке. Каждый вызов — это рейс по сети и сериализация параметров.
Что будет, если вернуть из сервера Структуру с объектом документа внутри?
Вызов завершится ошибкой целиком: клиент не получит даже те ключи структуры, что передаются нормально. Верните ссылку на документ, а нужные поля — отдельными ключами.