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