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