Как исправить ошибки при перепроведении документов 1С из C# через COM-соединение?

Программист IT и автоматизация бизнеса
← На главную

Интеграция приложений на C# с платформой 1С:Предприятие через COM-соединение — это классический сценарий взаимодействия систем. Однако при реализации этой схемы разработчики часто сталкиваются со специфическими ошибками, связанными с различиями в объектных моделях .NET и 1С. Типичный пример — попытка программно провести документ, которая завершается ошибками выполнения вроде "System.__ComObject" не содержит определения для "Записать" или некорректной передачей параметров проведения.

В этой статье мы подробно разберем, почему возникают такие проблемы, как правильно переводить ссылки на документы в объекты для записи и как безопасно передавать системные перечисления 1С через границу COM-интерфейса.

Анализ проблемы: Ссылка vs Объект в 1С

Разберем ситуацию, когда нам необходимо найти документ в базе данных 1С и перепровести его. Первой типичной ошибкой является попытка вызвать метод Записать() непосредственно у объекта, полученного в результате поиска (например, через НайтиПоНомеру()).

Выясним причину этой ошибки. В объектной модели 1С все данные разделены на ссылки и объекты:

Для того чтобы перейти от ссылки к объекту, в 1С используется метод ПолучитьОбъект(). Рассмотрим, как это выглядит на практике.

Проблема передачи системных перечислений через COM

Вторая сложность заключается в передаче параметров в метод Записать(). Встроенный язык 1С для проведения документа требует передачи специального системного перечисления: РежимЗаписиДокумента.Проведение. Разработчики, не знакомые с COM-клиентом 1С, часто пытаются передать этот параметр в виде строки:

order.Записать("РежимЗаписиДокумента.Проведение");

Такой код вызовет ошибку при выполнении. Дело в том, что C# и среда выполнения .NET не могут неявно преобразовать текстовую строку в специфический внутренний тип данных 1С. Все системные перечисления платформы 1С при работе через COM должны извлекаться непосредственно из самого COM-объекта соединения.

Пошаговое решение на C#

Проанализируем правильный алгоритм работы с COM-соединением 1С для поиска и успешного проведения документа. Мы инициализируем подключение, находим нужную ссылку, преобразуем её в объект и вызываем проведение, используя верный формат передачи перечисления.

Ниже представлен готовый пример кода на C#:


// Инициализируем COM-соединение (в примере используется версия платформы 8.2/8.3)
COMConnector com1s = new V82.COMConnector();
com1s.PoolCapacity = 10;
com1s.PoolTimeout = 60;
com1s.MaxConnections = 2;

// Устанавливаем подключение к базе данных (строка подключения ConV82 настраивается заранее)
dynamic connection = com1s.Connect(ConV82);

// Шаг 1: Находим ссылку на документ по номеру и дате
dynamic refer = connection.Документы.УстановкаЦенНоменклатуры.НайтиПоНомеру("00000011275", "05.12.2018 17:38:56");

// Проверяем, что ссылка не пустая
if (refer != null && !connection.ЗначениеЗаполнено(refer))
{
    Console.WriteLine("Документ не найден в базе данных.");
    return;
}

Console.WriteLine("Успешно найдена ссылка на документ №: " + refer.Номер);

// Шаг 2: Получаем изменяемый объект документа из ссылки
dynamic order = refer.ПолучитьОбъект();

// Шаг 3: Проводим документ, передавая перечисление из контекста COM-подключения
order.Записать(connection.РежимЗаписиДокумента.Проведение);

Console.WriteLine("Документ успешно перепроведен!");

В этом примере мы обращаемся к свойству connection.РежимЗаписиДокумента.Проведение. Это позволяет передать на сторону 1С легитимный COM-объект перечисления, который платформа успешно распознает.

Скрытые технические нюансы работы через COM-соединение

Хотя предложенное решение полностью закрывает локальную задачу перепроведения, при построении промышленных интеграционных решений на базе COM-технологий важно учитывать несколько неочевидных проблем:

  1. Разрядность процессов (32-bit vs 64-bit): Компонент comcntr.dll, обеспечивающий работу COMConnector, привязан к разрядности установленной платформы 1С. Если ваше .NET-приложение работает в 64-битном режиме, а на сервере установлена 32-битная версия клиента 1С (или наоборот), вы получите системную ошибку "Класс не зарегистрирован". Для решения этой проблемы часто приходится настраивать выделенный COM+ компонент в операционной системе Windows (внутри процесса dllhost.exe).
  2. Утечки памяти и незакрытые сессии: Сборщик мусора .NET (GC) не всегда своевременно уничтожает неуправляемые COM-объекты 1С. Это приводит к тому, что сессии пользователей "зависают" на сервере 1С, расходуя клиентские лицензии и оперативную память. Рекомендуется явно освобождать объекты после завершения работы с ними с помощью метода Marshal.ReleaseComObject(connection).
  3. Информативность ошибок: Если при проведении документа в 1С сработает проверка (например, "Недостаточно остатков на складе"), метод Записать() выбросит в C# общее исключение TargetInvocationException. Чтобы понять реальную причину отказа, вам придется оборачивать вызов в блок try-catch и анализировать системное описание ошибки через объект ИнформацияОбОшибке() на стороне 1С.

Современные альтернативы COM-подключению

Использование COM-соединения постепенно уходит в прошлое. Оно требует обязательного наличия установленной платформы 1С на клиентской машине, где запускается программа C#. Рассмотрим два более современных и надежных архитектурных подхода.

Вариант 1: Использование интерфейса OData (REST API)

Платформа 1С поддерживает автоматическую публикацию базы данных в формате стандартного интерфейса OData. В этом случае взаимодействие происходит по протоколу HTTP/HTTPS, что позволяет отправлять запросы из C#-приложений, развернутых в контейнерах Docker или под управлением Linux.

Для проведения документа через OData мы можем отправить POST-запрос на адрес публикации:


POST http://your-server/your-base/odata/standard.odata/Document_УстановкаЦенНоменклатуры(guid'идентификатор_документа')/Post?PostingModeOperational=false

Параметр PostingModeOperational=false сообщает системе, что документ необходимо провести в неоперативном режиме (задним числом). Это избавляет от необходимости писать сложный код управления транзакциями на стороне C#.

Вариант 2: Собственные HTTP-сервисы в 1С

Наиболее гибкий и рекомендуемый архитектурный подход — перенос всей бизнес-логики на сторону 1С. Вместо того чтобы манипулировать объектами 1С из внешнего кода, мы можем создать в конфигурации 1С собственный HTTP-сервис. Например, он будет принимать JSON с номером и датой документа.

В этом случае код на стороне 1С выполнит всю необходимую работу:


Функция ПровестиДокумент(Запрос)
    // Разбираем JSON, находим документ
    Ссылка = Документы.УстановкаЦенНоменклатуры.НайтиПоНомеру(НомерИзЗапроса, ДатаИзЗапроса);
    Если ЗначениеЗаполнено(Ссылка) Тогда
        Попытка
            Объект = Ссылка.ПолучитьОбъект();
            Объект.Записать(РежимЗаписиДокумента.Проведение);
            Возврат Новый HTTPСервисОтвет(200); // Успешно
        Исключение
            // Возвращаем текст ошибки проведения
            Возврат СформироватьОтветОбОшибке(ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
КонецФункции

На стороне C# при таком подходе остается лишь отправить простой HTTP-запрос через стандартный класс HttpClient. Это разделяет зоны ответственности разработчиков и упрощает поддержку кода в будущем.

← На главную