Разработка внешних компонент (ВК) для 1С на языке C# открывает огромные возможности для интеграции оборудования, однако часто сопровождается трудноуловимыми ошибками. Одной из самых частых проблем является аварийное закрытие процесса 1С при поступлении данных из SerialPort. Рассмотрим детально, почему это происходит и как построить надежную архитектуру взаимодействия.
Ошибка System.Reflection.TargetException: Объект не соответствует конечному типу при вызове событий из DataReceivedHandler — это классический симптом нарушения потоковой безопасности. Суть проблемы заключается в следующем:
DataReceived в классе SerialPort генерируется средой .NET в отдельном фоновом потоке из пула нитей (Thread Pool).testEvent() из обработчика события порта, вы пытаетесь «достучаться» до объектов 1С из «чужого» потока.Тот факт, что проблема проявляется на одних компьютерах и отсутствует на других, объясняется особенностями планировщика ОС и загрузкой процессора: иногда фоновому потоку «везет» выполнить вызов в нужный момент, но полагаться на это при разработке нельзя.
Современным стандартом надежности является вынос работы с «тяжелым» или нестабильным оборудованием во внешний процесс (микросервис). Рассмотрим плюсы такого подхода:
Как реализовать связь:
Вместо попытки заставить ВК «кричать» в 1С, настройте обмен через HTTP. 1С может периодически опрашивать микросервис, либо, если требуется мгновенное оповещение, опубликуйте HTTP-сервис на стороне 1С. В этом случае ваш микросервис при получении данных от считывателя просто отправляет POST-запрос на адрес опубликованного HTTP-сервиса 1С.
Если вы хотите сохранить текущую архитектуру с использованием ВК, необходимо правильно передать данные из фонового потока в основной поток 1С. Не вызывайте методы 1С напрямую из обработчика DataReceivedHandler.
Порядок действий:
ConcurrentQueue) внутри вашего класса компоненты.DataReceivedHandler только сохраняйте полученные данные в эту очередь.PostMessage (через Windows API), чтобы послать системное сообщение главному окну 1С.ОбработкаВнешнегоСобытия, внутри которой она безопасно заберет накопленные данные из вашей очереди через публичный метод компоненты.Этот метод исключает прямые вызовы из фоновых потоков и полностью устраняет причину «вылетов».
Это самый простой в реализации, но менее оперативный метод. Вы можете не генерировать события из ВК вообще, а хранить данные во внутреннем буфере (свойстве компоненты).
Алгоритм:
ПодключитьОбработчикОжидания с интервалом, например, 100-200 мс.ЕстьНовыеДанные().Истина, вызывайте ПолучитьДанные(), чтобы считать информацию из буфера.Этот способ позволяет избежать сложной синхронизации потоков, так как все вызовы происходят исключительно из основного потока 1С.
Выбирая между этими решениями, мы рекомендуем двигаться в сторону микросервисной архитектуры. Это позволит сделать вашу систему профессиональной, масштабируемой и, самое главное, устойчивой к сбоям оборудования.