Как вызвать методы сборки .NET и перехватить события в 1С 7.7

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

При интеграции платформы 1С 7.7 с современными веб-сервисами и сторонними протоколами разработчики нередко обращаются к возможностям платформы .NET через универсальные COM-обертки, такие как NetObjectToIDispatch45. Однако при попытке вызвать методы внешних библиотек (например, сборки FluorineFx для протокола AMF3) часто возникают специфические ошибки поиска методов через механизм рефлексии или сложности с получением возвращаемых данных. Разберем по шагам, почему возникают подобные сбои и как правильно организовать взаимодействие с .NET-классами в 1С 7.7.

Анализ ошибки вызова метода: «Не найден метод Connect»

Рассмотрим типовой сценарий, в котором возникает ошибка. При попытке выполнить следующий код в среде 1С 7.7:


net = СоздатьОбъект("NetObjectToIDispatch45");
сборка = net.ЗагрузитьСборку("C:\Program Files (x86)\FluorineFx\Bin\net\3.5\FluorineFx.dll");
_netConnection = net.СоздатьОбъект("FluorineFx.Net.NetConnection");

ObjectEncoding = net.ПолучитьТип("FluorineFx.ObjectEncoding");
_netConnection.ObjectEncoding = ObjectEncoding.AMF3;

_netConnection.Connect("http://127.0.0.1/instrument/eOrder/Amfphp/index.php");

Платформа возвращает исключение среды выполнения:

Ошибка в методе Connect Не найден метод "FluorineFx.Net.NetConnection.Connect". mscorlib

Выясним причину этой ошибки. В исходном коде библиотеки .NET сигнатура метода выглядит следующим образом:

public void Connect(string command, params object[] arguments)

Спецификатор params является синтаксическим сахаром языка C#. При компиляции он разворачивается в ожидание массива объектов System.Object[]. Механизм позднего связывания и диспетчеризации COM-обертки при передаче только одной строки пытается найти перегрузку метода с одним строковым аргументом Connect(string). Так как в сборке объявлен метод с двумя параметрами (строка и массив), поиск метода завершается неудачей.

Решение проблемы передачи аргументов переменной длины

Для успешного вызова метода необходимо явно сформировать и передать второй параметр — массив объектов нулевой длины. Рассмотрим два способа реализации.

Способ 1. Создание типизированного пустого массива

Сформируем массив нулевого размера типа System.Object средствами используемой компоненты и передадим его вторым аргументом:


net.УстЭтоСемерка();

// Создаем пустой массив типа System.Object
аргументы = net.СоздатьМассив("System.Object", 0);

// Вызываем метод с передачей обоих параметров
_netConnection.Connect("http://127.0.0.1/instrument/eOrder/Amfphp/index.php", аргументы);

Обратите внимание на вызов метода net.УстЭтоСемерка(): в среде 1С 7.7 отсутствует нативный тип Int32, и данный флаг переключает внутренние механизмы компоненты на корректную работу с числовыми типами семерки.

Способ 2. Использование универсального метода вызова

Если в компоненте поддерживается метод ВыполнитьМетод, рефлексивный вызов можно выполнить напрямую, передав объект, имя вызываемой функции и параметры:


net.ВыполнитьМетод(_netConnection, "Connect", "http://127.0.0.1/instrument/eOrder/Amfphp/index.php");

Организация подписки на события .NET в 1С 7.7

После вызова метода Connect соединение не возвращает результат синхронно. Библиотека FluorineFx проектировалась для асинхронного взаимодействия, поэтому статус подключения передается через события NetStatus, OnConnect и OnDisconnect.

В 1С 7.7 подписка на события объектов .NET реализуется через внешнюю компоненту взаимодействия с глобальным контекстом AddIn.GlobalContext1C и генерацию класса-обертки. Проанализируем схему подключения событий:

  1. Подключаем внешнюю компоненту контекста 1С и связываем ее с .NET-объектом.
  2. Создаем обертку событий через метод СоздатьОберткуДляСобытий77.
  3. Описываем функцию ОбработкаВнешнегоСобытия для приема системных уведомлений.
  4. Оставляем соединение открытым, чтобы дать возможность асинхронным потокам доставить событие в очередь Windows-сообщений 1С.

Посмотрим на практический пример кода формы или обработки:


Перем врап, ОберткаСобытий, _netConnection;

Функция СоздатьОбертку(ОбертываемыйОбъект)
    ПодключитьВнешнююКомпоненту("AddIn.GlobalContext1C");
    объект = СоздатьОбъект("AddIn.GlobalContext1C");
    ГлобальныйКонтекст = объект.ГлобальныйКонтекст;
    ОберткаСобытий = врап.СоздатьОберткуДляСобытий77(ОбертываемыйОбъект, ГлобальныйКонтекст);
КонецФункции

Функция NetStatus()
    Сообщить("Событие NetStatus: " + врап.ВСтроку(ОберткаСобытий.NetStatus));
КонецФункции

Функция OnConnect()
    Сообщить("Событие OnConnect: " + врап.ВСтроку(ОберткаСобытий.OnConnect));
КонецФункции

Функция OnDisconnect()
    Сообщить("Событие OnDisconnect: " + врап.ВСтроку(ОберткаСобытий.OnDisconnect));
КонецФункции

Функция ОшибкаСобытия()
    ПоследняяОшибка = ОберткаСобытий.ПоследняяОшибка;
    Сообщить("Ошибка в событии " + ПоследняяОшибка.Событие + ": " + врап.ВСтроку(ПоследняяОшибка.Исключение));
КонецФункции

Процедура ОбработкаВнешнегоСобытия(Источник, ИмяСобытия, Данные)
    Если Источник = "FluorineFx_Net_NetConnection" Тогда
        Шаблон("[" + ИмяСобытия + "()]");
    КонецЕсли;
КонецПроцедуры

Процедура ПриОткрытии()
    врап = СоздатьОбъект("NetObjectToIDispatch45");
    врап.УстЭтоСемерка();
КонецПроцедуры

Процедура ПодключитьсяКСерверу()
    ПутьКСборке = "C:\Program Files (x86)\FluorineFx\Bin\net\3.5\FluorineFx.dll";
    врап.ЗагрузитьСборку(ПутьКСборке);
    
    NetConnection = врап.ПолучитьТипИзСборки("FluorineFx.Net.NetConnection", ПутьКСборке);
    _netConnection = врап.СоздатьОбъект(NetConnection);
    
    // Создаем обертку до вызова сетевых методов
    СоздатьОбертку(_netConnection);
    
    ObjectEncoding = врап.ПолучитьТип("FluorineFx.ObjectEncoding");
    _netConnection.ObjectEncoding = ObjectEncoding.AMF3;
    
    аргументы = врап.СоздатьМассив("System.Object", 0);
    _netConnection.Connect("http://127.0.0.1/instrument/eOrder/Amfphp/index.php", аргументы);
    
    // Метод Close() вызывать сразу нельзя, иначе соединение закроется до получения ответа
КонецПроцедуры

Проблема реализации интерфейса обратного вызова (IPendingServiceCallback)

Следующая сложность при использовании метода Call заключается в получении возвращаемых бизнес-данных. Сигнатура вызова удаленной процедуры в FluorineFx выглядит так:


_netConnection.Call("Service.Method", new CallbackHandler(), new object[] { "параметр" });

Второй параметр метода ожидает объект, реализующий интерфейс IPendingServiceCallback с методом void ResultReceived(IPendingServiceCall call). Встроенный язык 1С 7.7 не поддерживает создание классов и непосредственную реализацию интерфейсов .NET. Попытка передать объект 1С напрямую вызовет ошибку несовместимости типов.

Для преодоления этого ограничения существуют следующие архитектурные подходы:

  1. Написание промежуточной C#-библиотеки (Фасада): Создается небольшая сборка-посредник, которая реализует интерфейс IPendingServiceCallback, вызывает асинхронный метод, ожидает ответ с помощью объектов синхронизации (ManualResetEvent) и возвращает готовый результат в 1С синхронно (например, в виде строки JSON или XML). Это самый стабильный и рекомендуемый способ.
  2. Динамическая компиляция обертки: Код класса C# с реализацией нужного интерфейса и генерацией внешнего события компилируется на лету через CSharpCodeProvider средствами компоненты враппера прямо из текста модуля 1С.
  3. Отказ от AMF3 в пользу REST/JSON: Если на сервере используется PHP (Amfphp), сервисные функции представляют собой обычные классы PHP. Параллельное добавление классического HTTP JSON-эндпоинта позволяет обращаться к веб-серверу из 1С 7.7 напрямую через стандартный COM-объект MSXML2.ServerXMLHTTP или WinHttp.WinHttpRequest.5.1, минуя сложности с бинарным протоколом и многопоточностью.
← На главную