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