При разработке и кастомизации конфигураций на платформе «1С:Предприятие 8.3» разработчики часто сталкиваются с ситуацией, когда код, успешно прошедший тесты в толстом клиенте или в файловом режиме, внезапно выдает ошибку Метод объекта не обнаружен при переходе в тонкий клиент. Особенно часто это происходит при попытке вызвать экспортную процедуру или функцию из одного общего модуля в другом.
В этой статье мы подробно разберем, почему возникает эта ошибка, как работает механизм компиляции общих модулей в системе 1С, и рассмотрим правильные архитектурные решения для исправления данной проблемы.
Рассмотрим конкретный сценарий. Из клиентского общего модуля УправлениеПечатьюУТКлиент (компилируется на клиенте) вызывается экспортная процедура ПараметрБезУслуг, расположенная в общем модуле ДоговораДействия (который должен выполняться на сервере). Код вызова выглядит следующим образом:
ДоговораДействия.ПараметрБезУслуг(ОписаниеКоманды.Идентификатор);
В толстом клиенте данный вызов отрабатывает штатно, но в тонком клиенте система выдает ошибку: Метод объекта не обнаружен (ПараметрБезУслуг). Проанализируем, какие механизмы платформы приводят к такому поведению.
Если у общего модуля (в нашем примере — ДоговораДействия) одновременно установлены флаги свойств «Клиент (управляемое приложение)» и «Сервер», платформа 1С компилирует два независимых экземпляра этого модуля:
Когда вызов метода происходит из клиентского контекста (из модуля УправлениеПечатьюУТКлиент), платформа руководствуется так называемым «правилом ближнего вызова» (приоритетом локального контекста). Видя, что у вызываемого модуля ДоговораДействия установлен флаг «Клиент», платформа обращается к его локальной клиентской копии на компьютере пользователя, даже не пытаясь отправить запрос на сервер.
Если при этом тело процедуры ПараметрБезУслуг внутри модуля ограничено инструкциями препроцессора для сервера, то на клиенте эта процедура просто отсутствует:
#Если Сервер Тогда
Процедура ПараметрБезУслуг(Идентификатор) Экспорт
// Данный код физически не компилируется на клиенте
КонецПроцедуры
#КонецЕсли
В результате клиентский экземпляр модуля компилируется без этого метода, что и приводит к ошибке Метод объекта не обнаружен.
Иногда разработчики ошибочно используют директивы компиляции (такие как &НаСервере) внутри общих модулей. Важно помнить следующее правило: директивы компиляции со знаком амперсанда (&) предназначены для модулей форм и команд, а в общих модулях они не работают или ведут себя непредсказуемо. Для управления компиляцией в общих модулях должны использоваться исключительно инструкции препроцессора, начинающиеся со знака решетки (#Если... #КонецЕсли).
В толстом клиенте (особенно при работе в файловом режиме базы данных) границы между клиентским и серверным окружением практически стёрты. Весь код выполняется в рамках одного общего процесса на локальном компьютере. Платформа маскирует ошибки контекстной видимости, позволяя клиентскому коду напрямую «дотягиваться» до серверных методов без явного вызова сервера. При переходе в реальную клиент-серверную архитектуру и тонкий клиент эти ошибки проектирования мгновенно проявляются.
Для устранения ошибки нам необходимо скорректировать настройки свойств общего модуля и структуру вызовов. Рассмотрим два основных способа решения.
Если вам необходимо быстро восстановить работоспособность доработанного модуля, выполните следующие действия в конфигураторе:
ДоговораДействия.Клиент (управляемое приложение).Сервер (если он не был установлен).Вызов сервера (Server Call). Это критически важно: именно данный флаг разрешает тонкому клиенту выполнять удаленный вызов серверных процедур этого модуля.Экспорт и не скрыта под инструкциями препроцессора, исключающими компиляцию на сервере.При такой настройке платформа поймет, что локальной клиентской копии модуля ДоговораДействия не существует, и автоматически перенаправит вызов ДоговораДействия.ПараметрБезУслуг(...) на сервер 1С.
Фирма «1С» в своих стандартах разработки (1С:ИТС) крайне не рекомендует смешивать клиентский и серверный контексты в одном общем модуле. Идеальным решением является разделение функционала на несколько специализированных модулей:
ДоговораДействияКлиент — модуль с включенным флагом Клиент. Содержит только клиентскую логику (открытие форм, интерактивные вопросы пользователю).ДоговораДействияСервер — модуль с включенным флагом Сервер. Не имеет флага Вызов сервера. Предназначен для внутренних серверных вызовов из других серверных модулей.ДоговораДействияВызовСервера — тонкий транзитный модуль с флагами Сервер и Вызов сервера. Он служит «мостом» для передачи вызовов с клиента на сервер.Рассмотрим пример правильной организации вызова через транзитный модуль:
В модуле ДоговораДействияВызовСервера (свойства: Сервер = Истина, Вызов сервера = Истина):
Процедура ПараметрБезУслуг(Идентификатор) Экспорт
// Перенаправляем вызов в основной серверный модуль
ДоговораДействияСервер.ПараметрБезУслуг(Идентификатор);
КонецПроцедуры
В модуле ДоговораДействияСервер (свойства: Сервер = Истина, Вызов сервера = Ложь):
Процедура ПараметрБезУслуг(Идентификатор) Экспорт
// Непосредственное выполнение бизнес-логики на сервере
// Здесь выполняются запросы к базе данных, работа со справочниками и т.д.
КонецПроцедуры
Такой подход минимизирует объем данных, передаваемых между клиентом и сервером, ускоряет работу системы в веб-клиенте и защищает конфигурацию от трудноуловимых ошибок компиляции.
После изменения свойств общих модулей в конфигураторе и обновления конфигурации базы данных тонкий клиент может продолжать выдавать старую ошибку. Это связано с тем, что платформа агрессивно кэширует метаданные (включая структуру и доступность общих модулей) на стороне пользователя.
Для гарантированного применения изменений выполните одно из следующих действий:
/ClearCache.%userprofile%\AppData\Local\1C\1cv8 и %userprofile%\AppData\Roaming\1C\1cv8).