Остановка цикла приложения во вторичном домене приложений - PullRequest
1 голос
/ 19 февраля 2010

Прежде всего, извиняюсь за длину ...

У меня есть приложение Host / Plugin, похожее на MAF.Мы не используем ни одно из System.Addin или связанных пространств имен, поскольку это настраиваемая архитектура подключаемых модулей с несколькими доменами приложений в игре.Host UI (пользовательский интерфейс) работает в своем собственном цикле приложений (AppDomain).При двойном щелчке элемента в представлении списка происходит следующее:

private static void StartPeripheralModule(string modName)
{
    AppDomain domain = AppDomain.CreateDomain(modName);
    // add to appdomains collection
    HostDomains[modName] = domain;

    // 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);

    // instance the adapter (inherits MBR)
    module.Adapter = new ModuleAdapter(modName, module);  // also saves a ref. to the IModule object

    // publish events decorated with [Serializable]
    module.Adapter.ModuleStarted += new ModuleAdapter.ModuleStartEventHandler(Adapter_ModuleStarted);
    module.Adapter.ModuleStopped += new ModuleAdapter.ModuleStopEventHandler(Adapter_ModuleStopped);
    module.Adapter.ModuleFaulted += new ModuleAdapter.ModuleFaultEventHandler(Adapter_ModuleFaulted);

    // add to adapters collection
    HostAdapters[modName] = module.Adapter;

    // asynchronous startup
    Action startup = module.Start;
    startup.BeginInvoke(null , null);
}

В module.Start():

[STAThread]
public void Start( )
{
    //  do Start
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    MdiForm = new UnitMDIForm();
    MdiForm.FormClosed += new FormClosedEventHandler(MdiForm_FormClosed);

    adapter.OnModuleStarted(new ModuleAdapter.ModuleStartEventArgs(adapter));

    Application.Run(MdiForm);
}

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

public static void UnloadInstance(string modName)
{
    Action shutdown = HostAdapters[modName].Module.Shutdown;
    IAsyncResult iaRes = shutdown.BeginInvoke(null , null);

    while (!iaRes.IsCompleted)  // poll wait state
    {
        Thread.Sleep(250);
        hostListener.Write(".");
    }
}

Функция выключения в плагине модуля:

public void Shutdown( )
{
    if (MdiForm.InvokeRequired)
    {
        MdiForm.Invoke((MethodInvoker)delegate
        {
            MdiForm.FormClosed -= MdiForm_FormClosed;
            Application.Exit();
        });
    }
    else
    {
        MdiForm.FormClosed -= MdiForm_FormClosed;
        Application.Exit();
    }

    adapter.OnModuleStopped(new ModuleAdapter.ModuleStopEventArgs(adapter));
}

Причина, по которой событие MdiForm.FormClosed не подписано наэто предотвратить двойную стрельбу.Как только Application.Exit() я получаю 1 - 2 '.'(точки) из механизма опроса, а затем:

Первое случайное исключение типа 'System.Threading.ThreadAbortException' произошло в mscorlib.dll Первое случайное исключение типа 'System.Threading.ThreadAbortException'произошло в UnitTestWinForm.dll Исключение типа «System.Threading.ThreadAbortException» произошло в UnitTestWinForm.dll, но не было обработано в коде пользователя

Излишне говорить, что мы никогда не достигнем нашего события OnModuleStopped, гдемы официально выгружаем AppDomain, удаляем его и адаптер из наших коллекций.Сейчас я вставляю блок try / catch, чтобы узнать, смогу ли я получить что-нибудь еще от ошибок.Из того, что я понимаю, я следую правильной процедуре при выходе из цикла сообщений приложения, а затем выгрузки домена.Это дает модулю возможность очищать свои ресурсы и т. Д.

Может кто-нибудь сказать мне, что я делаю неправильно и / или как я должен делать это по-другому?

1 Ответ

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

Это может помочь ...

В вашем приложении подпишитесь на:

        AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
        Application.ThreadException += ApplicationThreadException;

(см. Справку, они могут упростить ситуацию, но в других случаях в режиме отладки вы будетехочу отключить это)

Я не думаю, что вы должны вызывать Application.Exit () из модуля, он (насколько я знаю) закроет все приложение.

ВозможноПосмотрите, как такой инструмент, как NUnit, загружает и выгружает домены приложений - я никогда не пробовал выгружать один ....

PK: -)

...