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