Почему переменная модуля формы на сервере теряет свое значение и как правильно сохранить данные между вызовами

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Выясняем причину: бесстатейность (stateless) серверных вызовов

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

Каждый раз, когда выполняется процедура с директивой &НаСервере, происходит следующее:

  1. Клиент передает на сервер данные формы (сериализованный контекст реквизитов).
  2. На сервере создается новый временный экземпляр модуля формы.
  3. В этом новом экземпляре заново инициализируются все переменные, объявленные через ключевое слово Перем.
  4. Выполняется целевой код.
  5. Результат (обновленные данные формы) возвращается клиенту, а экземпляр модуля на сервере немедленно уничтожается.

Таким образом, значение переменной, установленное в одном вызове, физически исчезает вместе с удалением объекта модуля из оперативной памяти сервера. Использование ключевого слова Экспорт здесь не поможет, так как оно лишь расширяет область видимости переменной для других модулей в рамках одного и того же текущего вызова.

Решение №1: Использование реквизитов формы

Самый простой и правильный способ сохранить состояние — использовать реквизиты формы. В отличие от переменных модуля, реквизиты являются частью структуры данных, которая автоматически передается между клиентом и сервером (маршалинг данных). Рассмотрим, как это реализовать на практике.

Если вам нужно хранить данные, которые не должны видеть пользователи, выполните следующие действия:

  1. Откройте редактор формы на вкладке Реквизиты.
  2. Добавьте новый реквизит (например, ПараметрыДляРаботы).
  3. Укажите тип данных. Если структура данных сложная или заранее неизвестна, выберите тип Произвольный.

Теперь обращение к этим данным будет выглядеть так:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Сохраняем структуру параметров в реквизит формы
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("ДатаНачала", ТекущаяДата());
    СтруктураДанных.Вставить("РежимРаботы", "Расширенный");
    
    // Реквизит формы доступен всегда
    ЭтаФорма.ПараметрыДляРаботы = СтруктураДанных;
КонецПроцедуры

&НаСервере
Процедура ОбработатьДанныеНаСервере()
    // При втором вызове данные на месте
    Если ТипЗнч(ЭтаФорма.ПараметрыДляРаботы) = Тип("Структура") Тогда
        Сообщить("Режим: " + ЭтаФорма.ПараметрыДляРаботы.РежимРаботы);
    КонецЕсли;
КонецПроцедуры

Важный нюанс: Реквизиты формы с типом Произвольный не передаются на клиента. Они живут только в серверном воплощении формы. Если вам нужно иметь доступ к этим данным и на клиенте, используйте типы, поддерживающие сериализацию (Строка, Число, Структура, содержащая только простые типы).

Решение №2: Временное хранилище

Бывают ситуации, когда данные слишком тяжелые (например, большая таблица значений или двоичные данные) и передавать их туда-обратно между клиентом и сервером в реквизитах формы накладно для сети. В этом случае проанализируем механизм Временного хранилища.

Для того чтобы данные во временном хранилище были доступны до закрытия формы, их нужно привязать к уникальному идентификатору формы. Посмотрим на пример кода:


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

&НаСервере
Процедура ИзвлечьДанные()
    // Получаем данные по адресу
    ТЗ = ПолучитьИзВременногоХранилища(ЭтаФорма.АдресДанныхВХранилище);
    Если ТЗ <> Неопределено Тогда
        // Продолжаем работу с таблицей
    КонецЕсли;
КонецПроцедуры

При таком подходе данные лежат в оперативной памяти сервера (или во временных файлах сеанса) и не нагружают сетевой трафик при вызовах. Они будут автоматически удалены платформой при закрытии окна формы.

Различие контекстных вызовов: &НаСервере и &НаСервереБезКонтекста

Рассмотрим еще один важный аспект видимости — директивы компиляции. Проанализируем, как они влияют на доступ к данным:

Если вы объявили переменную в модуле формы как &НаСервере Перем МояПеременная;, она будет доступна только внутри вызовов &НаСервере (с контекстом), но, как мы выяснили ранее, только на период жизни этого конкретного вызова.

Сравнительный анализ контекста модуля и контекста формы

Часто путаница возникает из-за смешения понятий «Локальный контекст модуля» и «Контекст формы». Давайте внесем ясность:

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

Контекст формы — это реквизиты, которые вы создали в визуальном конструкторе. Они объединяют клиент и сервер. Платформа 1С берет на себя задачу синхронизации этих значений.

Если ваша задача — передать данные из ПриСозданииНаСервере в какой-нибудь ОбработчикСобытияНаСервере, который сработает позже при нажатии кнопки, единственный путь — использовать реквизит формы. При необходимости создавать такие реквизиты в коде доработок можно использовать конструктор для программной модификации управляемых форм.

Итоги и рекомендации

Подводя итог нашему анализу, сформулируем основные правила работы с переменными на сервере:

  1. Никогда не полагайтесь на переменные модуля (Перем) для хранения состояния между разными серверными вызовами. Они предназначены только для временных расчетов внутри одной процедуры.
  2. Для хранения настроек, параметров и состояний формы всегда создавайте Реквизиты формы.
  3. Если данные «секретные» или системные — просто не выносите этот реквизит на визуальную часть формы (в дерево элементов), и пользователь о нем не узнает.
  4. Для работы с объектами, которые нельзя хранить в реквизитах (например, COM-объекты или ТаблицыЗначений в некоторых случаях), используйте Временное хранилище с привязкой к идентификатору формы.
  5. Помните, что клиентская переменная (&НаКлиенте Перем...) сохраняет значение всё время, пока открыта форма, но она недоступна на сервере. Если данные нужны и там, и там — реквизит формы незаменим.

Используя эти принципы, мы обеспечиваем стабильную работу приложения в любых условиях, включая работу в веб-клиенте и в кластерах серверов с распределенной нагрузкой.

← На главную