Соответствует ли COM-взаимодействие границам .NET AppDomain при загрузке сборки?

StackOverflow https://stackoverflow.com/questions/242391

Вопрос

Вот основная проблема: у меня есть приложение .NET, которое использует COM-взаимодействие в отдельный домен приложений. Кажется, что COM-компонент загружает сборки обратно в домен по умолчанию, а не в домен приложений, из которого вызывается COM-компонент.

Я хочу знать следующее: это ожидаемое поведение или я делаю что-то не так, чтобы эти связанные с COM сборки загружались не в тот домен приложений? Пожалуйста, смотрите более подробное описание ситуации ниже ...

Приложение состоит из 3 сборок: - основной EXE, точка входа в приложение. - common.dll, содержащая только интерфейс IController (в стиле IPlugin) - controller.dll, содержащий класс Controller, который реализует IController и MarshalByRefObject. Этот класс выполняет всю работу и использует взаимодействие COM для взаимодействия с другим приложением.

Соответствующая часть основного EXE-файла выглядит следующим образом:

AppDomain controller_domain = AppDomain.CreateDomain("Controller Domain");
IController c = (IController)controller_domain.CreateInstanceFromAndUnwrap("controller.dll", "MyNamespace.Controller");
result = c.Run();
AppDomain.Unload(controller_domain);

Common.dll содержит только эти 2 вещи:

public enum ControllerRunResult{FatalError, Finished, NonFatalError, NotRun}
public interface IController
{
    ControllerRunResult Run();
}

И контроллер.dll содержит этот класс (который также вызывает взаимодействие COM):

public class Controller: IController, MarshalByRefObject

При первом запуске приложения Assembly.GetAssemblies () выглядит так, как ожидается, при этом common.dll загружается в оба домена приложений, а controller.dll загружается только в домен контроллера. Однако после вызова c.Run () я вижу, что сборки, связанные с взаимодействием COM, были загружены в домен AppDomain по умолчанию, а НЕ в домен AppDomain, с которого происходит взаимодействие COM.

Почему это может происходить?

А если вам интересно, вот немного предыстории:

Первоначально это было 1 приложение AppDomain. COM-интерфейс, с которым он взаимодействует, является серверным API, который не стабилен в течение длительного периода использования. Когда COMException (без полезной диагностической информации относительно его причины) происходит из COM-компонента, все приложение должно быть перезапущено, прежде чем COM-соединение снова заработает. Простое повторное подключение к серверу приложений COM снова приводит к немедленным исключениям COM. Чтобы справиться с этим, я попытался переместить компонент взаимодействия COM в отдельный AppDomain, чтобы при возникновении таинственных исключений COMException я мог выгрузить AppDomain, в котором он возник, создать новый и начать заново, и все это без необходимости перезапуска приложения вручную. , Так или иначе, это была теория ...

Это было полезно?

Решение

К сожалению, компонент COM загружается в пространстве процессов, а не в контексте домена приложения. Таким образом, вам нужно будет вручную разорвать (освободить и разгрузить) ваши собственные библиотеки DLL (относится как к COM, так и к P / Invoke). Простое уничтожение домена приложения не принесет вам пользы, но повторное порождение всего процесса не должно быть необходимым для сброса состояния COM (простое воссоздание COM-объектов также должно нормально работать, это звучит как ошибка в коде поставщиков компонентов, возможно, они могут решить это?)

Ссылки

(TechNet) адресное пространство процесса

(MSDN) Домены приложений

(MSDN) Границы: процессы и домены приложений

Другие советы

Вот доказательство того, что ответ Шона Уилсона правильный

Домен приложения Com

Не делайте MBR вашего контроллера. Создайте небольшой прокси-сервер, который загружает контроллер во второй домен и запускает его. Таким образом, dll контроллера не будет загружен в первом домене.

scroll top