Почему нельзя использовать директиву &НаСервереБезКонтекста в общих модулях 1С и как это исправить?

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

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

Разберем техническую причину ошибки «Метод не найден»

Проанализируем ситуацию: у нас есть общий модуль с установленными признаками «Сервер» и «Вызов сервера». Разработчик добавляет в него процедуру и по аналогии с модулем формы помечает её директивой &НаСервереБезКонтекста. Казалось бы, логика верна — мы хотим выполнить код на сервере без лишних данных. Однако при попытке вызвать эту процедуру из модуля формы 1С выдает ошибку.

Выясним причину: директивы компиляции (&НаКлиенте, &НаСервере, &НаСервереБезКонтекста) предназначены исключительно для модулей, обладающих расширением (это модули управляемых форм и модули команд). Когда компилятор 1С встречает такую директиву в общем модуле, он обрабатывает её некорректно для механизма экспорта. В результате, несмотря на наличие слова Экспорт, метод не регистрируется в таблице доступных методов модуля для внешних вызовов. Именно поэтому система сообщает, что метод не найден.

Понятие контекста: Форма против Общего модуля

Чтобы понять, почему использование &НаСервереБезКонтекста в общем модуле лишено смысла, разберем, что такое контекст в 1С. В платформе существует два принципиально разных вида контекста:

  1. Контекст формы: это совокупность всех реквизитов формы, её элементов, переменных модуля и параметров. Когда в модуле формы мы вызываем процедуру &НаСервере, 1С упаковывает всю форму (все её данные), передает на сервер, выполняет код и возвращает измененную форму обратно. Это «тяжелая» операция. Директива &НаСервереБезКонтекста в форме нужна именно для того, чтобы не передавать эти данные, работая только с переданными параметрами.
  2. Глобальный контекст и контекст модуля: Общий модуль по своей природе не имеет контекста формы. Он не «знает», из какой формы его вызвали, и не имеет доступа к её реквизитам напрямую.

Проанализируем ситуацию: любой вызов процедуры общего модуля (если он серверный) — это уже по определению вызов без контекста формы. Попытка добавить директиву &НаСервереБезКонтекста в общий модуль — это «масло масляное», которое к тому же ломает компиляцию метода.

Проанализируем стандарты разработки 1С (ИТС)

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

Во-первых, в серверных или клиентских общих модулях контекст исполнения очевиден из настроек самого модуля (галочки в свойствах). Применение директив внутри таких модулей только запутывает разработчика.

Во-вторых, если модуль помечен одновременно и как «Клиент», и как «Сервер», использование директив компиляции (&НаКлиенте и т.д.) вместо инструкций препроцессора (#Если Сервер Тогда) затрудняет понимание того, в какой среде окажется процедура. Стандарты требуют разделять такой код с помощью инструкций препроцессора.

Как правильно заменить директивы в общем модуле

Посмотрим на пример того, как делать нельзя:


// В общем модуле (НЕПРАВИЛЬНО)
&НаСервереБезКонтекста
Процедура МояПроцедура(Параметр) Экспорт
    // Какой-то код
КонецПроцедуры

Рассмотрим, как правильно организовать этот же код. Если ваш модуль чисто серверный, достаточно просто убрать директиву:


// В общем модуле (ПРАВИЛЬНО)
Процедура МояПроцедура(Параметр) Экспорт
    // Этот код и так выполнится на сервере без контекста формы
КонецПроцедуры

Если же ваш общий модуль является общим для клиента и сервера (стоят обе галочки), и вы хотите, чтобы процедура была доступна только на сервере, используйте инструкции препроцессора:


// В общем модуле (ПРАВИЛЬНО для Клиент-Серверного модуля)
#Если Сервер Тогда
Процедура МояПроцедура(Параметр) Экспорт
    // Этот код скомпилируется только на сервере
КонецПроцедуры
#КонецЕсли

Проблема с функцией РольДоступна и глобальным контекстом

Автор темы упомянул, что в процедурах «без контекста» перестает работать функция РольДоступна(). Выясним причину. На самом деле, эта функция доступна в глобальном контексте и на клиенте, и на сервере. Однако, когда вы ошибочно используете &НаСервереБезКонтекста в общем модуле, вы создаете «битый» контекст выполнения. Платформа ожидает одного поведения, а получает другое.

Если вы уберете неверную директиву и оставите метод просто серверным (в серверном общем модуле), функция РольДоступна() будет работать штатно. Стоит помнить, что на сервере РольДоступна() проверяет права текущего пользователя сеанса, и это стандартное поведение для серверного вызова.

Выводы и рекомендации

Подведем итоги нашего исследования:

  1. Никогда не используйте директивы &НаКлиенте, &НаСервере, &НаСервереБезКонтекста внутри общих модулей. Это приводит к ошибкам исполнения и нарушает логику компиляции.
  2. Разграничивайте контекст с помощью свойств самого общего модуля. Если код должен быть только на сервере — создайте отдельный модуль с галочкой «Сервер».
  3. Используйте инструкции препроцессора (#Если Сервер Тогда, #Если Клиент Тогда), если возникла острая необходимость держать клиентский и серверный код в одном модуле (хотя 1С рекомендует их разделять).
  4. Помните об оптимизации: вызов серверного общего модуля из формы всегда эффективнее, чем вызов &НаСервере процедуры самой формы, так как общий модуль не гоняет данные формы (контекст) по сети туда-обратно.

Таким образом, для решения проблемы автора достаточно просто удалить строку &НаСервереБезКонтекста из общего модуля. Весь функционал сохранится, а ошибка «Метод не найден» исчезнет, так как метод станет корректно экспортируемым.

← На главную