Почему общий модуль 1С не видит свою процедуру при вызове с клиента на сервер?

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

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

Рассмотрим эту проблему подробно, разберем причины такого поведения платформы и изучим правильные архитектурные подходы для реализации подобных вызовов.

Анализ ситуации: почему директивы компиляции не работают в общих модулях

Главная причина кроется в фундаментальном различии между модулями управляемых форм и общими модулями. Проанализируем, как платформа обрабатывает код в обоих случаях.

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

В общих модулях ситуация иная. Директивы &НаКлиенте и &НаСервере там просто не работают как переключатели контекста. Если вы установили у общего модуля флаги Клиент (управляемое приложение) и Сервер, платформа компилирует этот модуль дважды:

  1. Один раз для клиента — в этот экземпляр попадает только тот код, который доступен в клиентском контексте.
  2. Второй раз для сервера — туда попадает код, доступный серверу.

Когда вы пишете внутри общего модуля следующий код:


&НаКлиенте
Процедура ВыполнитьДействиеНаКлиенте()
    ВыполнитьНаСервере(); // Ошибка: метод не обнаружен
КонецПроцедуры

&НаСервере
Процедура ВыполнитьНаСервере()
    // Какая-то логика
КонецПроцедуры

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

Выясняем причину: синтаксический контроль против рантайма

Многих сбивает с толку тот факт, что проверка модуля (Ctrl+F7) проходит успешно. Разберем, почему так происходит. При проверке конфигуратор по очереди эмулирует разные контексты. Сначала он проверяет код с точки зрения сервера — серверная процедура на месте, вызов корректен. Затем с точки зрения клиента — если директива &НаСервере не распознана как ошибка синтаксиса (а она воспринимается как законная инструкция в контексте форм), проверка может пройти. Однако в момент исполнения (Runtime) в тонком клиенте серверной части кода физически нет в оперативной памяти клиентского процесса.

Решение №1: Разделение модулей по стандартам разработки 1С

Самый правильный и рекомендуемый фирмой 1С способ — это разделение функциональности на разные специализированные модули. Это позволяет избежать путаницы в контекстах и упрощает поддержку кода. Рассмотрим стандартную схему организации модулей:

  1. ИмяМодуляКлиент: Флаг Клиент (управляемое приложение). Здесь располагается логика взаимодействия с пользователем (сообщения, вопросы, открытие форм).
  2. ИмяМодуляСервер: Флаг Сервер. Здесь находится вся логика работы с базой данных, запросы и обработка данных.
  3. ИмяМодуляВызовСервера: Флаги Сервер и Вызов сервера. Этот модуль служит «шлюзом» (API).

Пример правильной реализации вызова:

В модуле ОбменДаннымиКлиент:


Процедура ПрочитатьРезультатыОбмена() Экспорт
    // Вызываем серверный метод через специальный модуль-шлюз
    Если ОбменДаннымиВызовСервера.ЭтоПользовательРегламентногоЗадания() Тогда
        Сообщить("Работа под системной учетной записью");
    КонецЕсли;
КонецПроцедуры

В модуле ОбменДаннымиВызовСервера (флаги: Сервер, Вызов сервера):


Функция ЭтоПользовательРегламентногоЗадания() Экспорт
    Возврат Пользователи.ТекущийПользователь() = Справочники.Пользователи.НайтиПоНаименованию("РегламентныйЗаказ");
КонецФункции

Решение №2: Использование инструкций препроцессора

Если вы все же хотите оставить код в одном модуле (что допустимо для небольших утилит, но не рекомендуется для крупных систем), необходимо использовать инструкции препроцессора вместо директив компиляции. Инструкции начинаются с символа #.

Проанализируем разницу: директива & говорит, где метод может исполняться, а инструкция #Если буквально вырезает или оставляет куски текста программы перед тем, как превратить их в исполняемый код.


#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Функция ЭтоПользовательРегламентногоЗадания() Экспорт
    // Серверная логика
    Возврат Истина;
КонецФункции
#КонецЕсли

Однако помните: использование инструкций препроцессора внутри одного модуля не решит проблему вызова серверного метода с тонкого клиента. Тонкий клиент по-прежнему не сможет «дотянуться» до кода, обернутого в #Если Сервер, без использования флага Вызов сервера и обращения через имя модуля.

Решение №3: Обращение через имя модуля

Как отметили участники обсуждения, иногда помогает явное указание пути к процедуре, даже если она находится в этом же модуле. Но это работает только при включенном флаге «Вызов сервера» у данного модуля.

Рассмотрим пример:


// В общем модуле "МойМодуль" с установленными флагами: 
// Клиент, Сервер, Вызов сервера

Процедура КлиентскийМетод() Экспорт
    // Прямой вызов СерверныйМетод() приведет к ошибке
    // А вызов через имя модуля инициирует серверный звонок
    МойМодуль.СерверныйМетод(); 
КонецПроцедуры

Процедура СерверныйМетод() Экспорт
    // Логика на сервере
КонецПроцедуры

Важно понимать: такой подход заставляет систему делать полноценный вызов сервера (network round-trip), даже если вы технически находитесь внутри одного и того же текстового файла модуля. Это менее производительно, чем разделение на специализированные модули, так как клиентскому приложению приходится кэшировать весь объем модуля (включая серверные процедуры), что увеличивает потребление памяти.

Подведем итоги

Для стабильной и производительной работы управляемого приложения рекомендуем придерживаться следующих правил:

Соблюдение этих архитектурных принципов избавит вас от ошибок «Метод не обнаружен» и сделает код вашей конфигурации соответствующим стандартам качества фирмы «1С».

← На главную