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