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