При разработке механизмов обмена данными между базами 1С с использованием технологии COM-соединения программисты часто сталкиваются с ситуацией, когда код в базе-источнике выполняется корректно, но при попытке вызвать метод Записать() для объекта в базе-приемнике возникает исключение — для этого есть готовая настройка двустороннего обмена через COM-соединение. Ситуация осложняется тем, что стандартная отладка не всегда «подхватывает» внешнее соединение, а текст ошибки кажется малоинформативным. Рассмотрим подробно, как настроить среду для поиска таких ошибок и как их устранять.
Типичная ошибка, возникающая при записи документа через COMConnector, выглядит так: «Попытка передачи с клиента на сервер мутабельного значения 1-го параметра метода ДокументОбъектПриЗаписи». Проанализируем причину ее возникновения. В архитектуре 1С внешнее соединение (COM) выступает в роли особого вида клиента. Когда мы вызываем метод Записать() через COM-объект, управление передается в базу-приемник. Если в этой базе настроены подписки на события (например, ПриЗаписи), платформа пытается выполнить код соответствующего обработчика.
Проблема кроется в том, что если обработчик расположен в общем модуле, у которого не установлен флаг Внешнее соединение, платформа пытается передать управление на сервер. Однако в качестве параметра передается сам ДокументОбъект. Поскольку ДокументОбъект является мутабельным типом (изменяемым объектом), его передача между контекстом внешнего соединения (клиентом) и сервером запрещена. Это и порождает исключение.
Первым делом нам необходимо проверить свойства модулей в базе-приемнике. Выясним, какие подписки на события срабатывают при записи проблемного документа. Для этого выполним следующие шаги:
Документ или Справочник), при записи которого возникает ошибка.ПриЗаписи или ПередЗаписью.Важный момент: если внутри этого модуля вызываются функции из других общих модулей, для них также может потребоваться установка данного флага. Проанализируем цепочку вызовов, чтобы убедиться, что весь контекст доступен для COM-соединения без пересечения границы «клиент-сервер» внутри базы-приемника.
Если простая проверка флагов не помогла, нам потребуется пошаговая отладка в базе-приемнике — для этого пригодится инструмент пошаговой отладки кода без конфигуратора. Для того чтобы отладчик смог перехватить выполнение кода, инициированного через COM, проделаем следующие манипуляции:
Рассмотрим настройку на стороне базы-приемника:
Теперь, когда база-источник инициирует подключение, в списке доступных предметов отладки должно появиться «Внешнее соединение». После этого точки останова, установленные в модуле объекта или в общих модулях (с флагом Внешнее соединение), начнут срабатывать.
Иногда ошибка возникает в типовых механизмах, которые сложно или нежелательно модифицировать. Если наша задача — просто перенести данные, и мы уверены в их корректности, мы можем использовать свойство ОбменДанными.Загрузка. Рассмотрим пример кода в базе-источнике:
// Предположим, V8 — это наше установленное соединение с базой-приемником
НовыйДокумент = V8.Документы.ЗаказПоставщику.СоздатьДокумент();
// Заполнение реквизитов...
НовыйДокумент.Дата = ТекущаяДата();
// Установка режима загрузки для обхода подписок и проверок
НовыйДокумент.ОбменДанными.Загрузка = Истина;
Попытка
НовыйДокумент.Записать();
Исключение
Сообщить("Ошибка при записи через COM: " + ОписаниеОшибки());
КонецПопытки;
Установка ОбменДанными.Загрузка = Истина позволяет отключить большинство стандартных подписок на события и проверок в модуле объекта, что часто помогает избежать «мутабельных» ошибок в коде, не адаптированном под внешние соединения.
Выясним разницу между способами подключения. В 1С существует два основных способа создания COM-объекта: V83.COMConnector и V83.Application. Рассмотрим их особенности:
Application позволяет обойти проблемы, возникающие в COMConnector, так как среда выполнения становится ближе к обычному клиентскому сеансу.Пример инициализации соединения через COMConnector, который мы рассматриваем:
Функция УстановитьСоединение(ПараметрыСвязи)
Попытка
Connector = Новый COMObject("V83.COMConnector");
СтрокаСоединения = "Srvr=""" + ПараметрыСвязи.Сервер + """;Ref=""" + ПараметрыСвязи.База + """;Usr=""" + ПараметрыСвязи.Пользователь + """;Pwd=""" + ПараметрыСвязи.Пароль + """";
Возврат Connector.Connect(СтрокаСоединения);
Исключение
Сообщить("Не удалось подключиться: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
В случаях, когда отладчик не помогает (например, если ошибка происходит на очень ранних этапах или в закрытом коде), проанализируем ситуацию с помощью Технологического журнала. Для этого нужно создать файл logcfg.xml на сервере базы-приемника. Настроим сбор событий ошибок EXCP. В логах мы увидим полный стек вызова (Call Stack) в момент возникновения ошибки «Попытка передачи мутабельного значения». Это позволит точно определить строку кода и модуль, которые вызывают проблему.
Резюмируем: для успешной отладки и работы через COM необходимо обеспечить доступность программного кода для внешнего соединения (флаги модулей), правильно настроить автоматическое подключение предметов отладки в конфигураторе и, при необходимости, использовать режим Загрузка = Истина для минимизации влияния побочных серверных обработчиков.