AppDomain Unload убивает родительский AppDomain - PullRequest
8 голосов
/ 19 февраля 2010

У меня проблемы с выяснением чего-то в моем AppDomain.Unload(...) звонке.У меня есть подробное объяснение с кодом из моего предыдущего вопроса .Оказывается, я выполнил пару шагов, которые, по-видимому, мне не нужны.Однако я совершенно уверен, что когда домен приложения создается и затем хранится в коллекции:

private static Dictionary<string , AppDomain> HostDomains;

void StartNewDomain(string domainName)
{
    AppDomain domain = AppDomain.CreateDomain(domainName);
    HostDomains[domainName] = domain;
}

... когда вы закончите с ним, вы должны его выгрузить:

if (HostDomains.ContainsKey(domainName))
{
    AppDomain.Unload(HostDomains[domainName]);
    HostDomains.Remove(domainName);
}

, а затем удалить домен из коллекции.

Однако когда я выгружаю домен, все приложение заканчивается.Если я удаляю выгрузку, все хорошо ... и мы просто остаемся с удалением домена из коллекции.Но я боюсь, что мой дочерний домен AppDomain не действительно выгружен.Это может в конечном итоге получить GC, я думаю, но это не дает мне теплый нечеткий.

Дочерняя сборка AppDomain (приложение Windows Form) запускается асинхронно через интерфейс (IModule), на который ссылается мой класс адаптера, который наследует MarshalByRefObject.Мне интересно, если эта ссылка на IModule Start () (которую реализует сборка модуля плагина) не выполняет маршалинг должным образом (из-за моей реализации).Итак, когда вызывается метод Shutdown (), все приложение умирает.Должен ли я сделать мой IModule абстрактным классом, чтобы он также наследовал MBR?Озадаченный ...

После просмотра моего кода:

// instances the module for access to the module's Start() method
    IModule module = (IModule)domain.CreateInstanceAndUnwrap(
    ModuleManager.Modules[modName].Name, 
    ModuleManager.Modules[modName].EntryPoint.FullName);

... я боюсь, что, поскольку IModule является интерфейсом, хотя я создаю экземпляр в дочернем домене,сборка просачивается в мой основной домен приложений.Поэтому, когда я пытаюсь выгрузить дочерний домен, оба домена выгружаются.Было бы это правильно?И что может быть лучшим решением для предоставления методов Start () и Stop () через объект MBR (адаптер)?

ОБНОВЛЕНИЕ: см. Мой ответ ниже для изменений -
Хорошо, нет утечки - все наследует MBR:

  1. Хост: MarshalByRefObject - экземпляры ModuleAdapter вновый AppDomain
  2. ModuleAdapter: MarshalByRefObject - интерфейс IModule, методы интерфейса (Start, Stop)
  3. MyModulePlugin: MarshalByRefObject - Application.Run (myForm)

AmЯ все еще делаю что-то не так?Я пробовал несколько вещей, и это только кажется неправильным или неполным.Когда я сообщаю ModuleAdapter о завершении работы, он вызывает AppDomain.Unload(AppDomain.CurrentDomain), и домен хоста также останавливается.Я все еще получаю некоторые исключения из первого шанса при выходе из приложения.Но форма (myForm) была сообщена .Close ().

Итак, я все еще ищу правильный способ сделать это ...

1 Ответ

1 голос
/ 19 февраля 2010

Как я и подозревал, создание экземпляра с интерфейсом IModule в основном домене вызывает утечку. Для того, чтобы сделать это правильно:

AppDomain domain = AppDomain.CreateDomain(domainName);
HostDomains[domainName] = domain;  // put in collection

ModuleAdapter adapter = (ModuleAdapter)domain.CreateInstanceAndUnwrap(asmName , typeName);

, где ModuleAdapter наследует MarshalByRefObject. Тогда:

adapter.Execute(moduleAssembly , moduleType);

Внутри класса ModuleAdapter:

public void Execute(string Name, string EntryPoint)
{
    module  = (IModule)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(Name , EntryPoint);
}

Я приветствую комментарии или дополнительные ответы для лучшего способа.

После перемещения экземпляра в класс ModuleAdapter у нас все еще остается проблема с AppDomain.Unload, убивающим все приложение. Мне было интересно, если это потому, что в модуле плагина мы используем Application.Run(myForm) - тогда, когда мы выключаем, мы вызываем myForm.Close (). Очевидно, это закрывает приложение, поэтому мне было интересно, если myForm.Close () также «выгружает» домен приложения.

...