Как сохранить COM-соединение между серверными вызовами в управляемой форме 1С 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Разберем, почему попытки сохранить COM-объект на сервере между вызовами терпят неудачу, и рассмотрим архитектурно правильные способы решения этой задачи.

Почему COM-соединение нельзя сохранить на сервере управляемой формы

Посмотрим на внутреннее устройство клиент-серверной архитектуры 1С:Предприятия. При работе с управляемыми формами каждый вызов с клиента на сервер через &НаСервере или &НаСервереБезКонтекста является независимым (stateless-архитектура). В кластере серверов 1С последовательные запросы одного и того же пользователя могут обрабатываться разными рабочими процессами rphost.

Проанализируем технические ограничения платформы:

  1. Несериализуемость объекта: Тип COMОбъект представляет собой указатель операционной системы Windows. Платформа 1С не умеет сериализовать такие системные дескрипторы. По этой причине его невозможно сохранить в реквизитах формы, параметрах сеанса или поместить во временное хранилище через метод ПоместитьВоВременноеХранилище().
  2. Сброс кэша: Общие модули с повторным использованием возвращаемых значений также не гарантируют сохранение внешнего COM-указателя: при очистке кэша или передаче запроса на другой серверный процесс обращение к объекту вызовет критическую ошибку.
  3. Блокировка лицензий: Каждое активное COM-соединение занимает отдельную клиентскую лицензию в базе-приемнике на все время удержания подключения.

Решение 1. Переход на HTTP-сервисы или Web-сервисы (Рекомендуемый подход)

Рассмотрим самое надежное и современное решение: замена тяжелого COM-соединения на веб-технологии. База-источник публикуется на веб-сервере (IIS или Apache), и в ней создается легковесный HTTP-сервис, отдающий остатки номенклатуры в формате JSON.

В отличие от устаревших SOAP Web-сервисов, платформенные HTTP-сервисы 1С обрабатывают запросы быстрее и не создают избыточных XML-оберток. Вызов HTTP-запроса на сервере формы выполняется за доли секунды и не требует постоянного удержания соединения.

Разберем по шагам реализацию запроса на клиенте и сервере текущей базы:


&НаСервереБезКонтекста
Функция ПолучитьОстатокТовараЧерезHTTP(КодНоменклатуры)
    
    Сервер = "api.company.local";
    ЗащищенноеСоединение = Неопределено;
    Соединение = Новый HTTPСоединение(Сервер, 443, "Логин", "Пароль", , 10, ЗащищенноеСоединение);
    
    Запрос = Новый HTTPЗапрос("/base2/hs/stocks/get?code=" + КодНоменклатуры);
    Ответ = Соединение.Получить(Запрос);
    
    Если Ответ.КодСостояния = 200 Тогда
        ЧтениеJSON = Новый ЧтениеJSON;
        ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
        Данные = ПрочитатьJSON(ЧтениеJSON);
        Возврат Данные.Остаток;
    Иначе
        ВызватьИсключение "Ошибка получения остатка: " + Ответ.КодСостояния;
    КонецЕсли;
    
КонецФункции

Решение 2. Использование стандартного интерфейса OData

Проанализируем ситуацию, когда дорабатывать вторую информационную базу и писать собственные HTTP-сервисы запрещено. В этом случае в целевой базе достаточно опубликовать стандартный интерфейс OData.

Платформа 1С автоматически сформирует REST API ко всем объектам и виртуальным таблицам базы. Запрос остатков по конкретной номенклатуре отправляется стандартным объектом HTTPСоединение напрямую к виртуальной таблице остатков регистра накопления. Это избавляет от необходимости инициализировать COM-коннектор и не требует модификации конфигурации второй базы.

Решение 3. Использование долгоживущего фонового задания (Worker)

Если интеграция обязана работать исключительно через COM-соединение, применим паттерн фонового процесса. Фоновое задание запускается на сервере один раз и непрерывно держит COM-соединение в рамках одного потока.

Выясним логику взаимодействия формы и фонового задания:

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

Решение 4. Вызов COM-соединения на стороне клиента

Рассмотрим вариант, упомянутый участниками обсуждения: создание и хранение COM-объекта в модуле управляемого приложения или в переменной формы на стороне клиента. Обратите внимание: этот способ имеет существенные архитектурные ограничения.

Разберем ограничения клиентского COM-соединения:

  1. Работает только в среде Windows под управлением тонкого или толстого клиента.
  2. Полная неработоспособность в веб-клиенте (через браузер), а также на клиентских рабочих станциях под управлением Linux и macOS.
  3. Требуется строгая совместимость разрядности: разрядность клиента 1С (x86 или x64) должна точно совпадать с разрядностью зарегистрированной в системе библиотеки comcntr.dll.

Пример инициализации соединения в переменной модуля управляемого приложения на клиенте:


// В модуле управляемого приложения
Переменная глВнешнееСоединение Экспорт;

Процедура ПриНачалеРаботыСистемы()
    #Если Клиент И Не ВебКлиент Тогда
        Попытка
            Коннектор = Новый COMОбъект("V83.COMConnector");
            глВнешнееСоединение = Коннектор.Connect("Srvr=""Server1C"";Ref=""TargetBase"";Usr=""User"";Pwd=""Password"";");
        Исключение
            Сообщить("Не удалось установить COM-соединение: " + ОписаниеОшибки());
        КонецПопытки;
    #КонецЕсли
КонецПроцедуры

При таком подходе форма обращается напрямую к переменной глВнешнееСоединение без необходимости каждый раз тратить время на авторизацию во внешней базе.

← На главную