强大的架构/库,用于强大的插件/插件管理

时间:2011-03-31 01:03:46

标签: .net architecture plugins error-handling crash-recovery

我们有一个应用程序,作为其要求之一,它将采用任意第三方插件,加载它们,并在我们自己开发的应用程序旁边运行它们的UI。我们一直在将这些第三方插件加载到他们自己的AppDomain中以实现隔离,一切正常。

直到其中一个插件因未处理的异常而崩溃。在这种情况下,整个应用程序都会关闭,即使所有真正受到影响的应用程序都是我们的“额外”工具窗口之一。

理想情况下,我们想要一些方法来处理“未处理的”异常,卸载损坏的AppDomain,然后重新加载它。问题是我们找不到机制在未处理异常的事件处理程序中,我们可以将异常标记为“已处理”。此外,由于插件具有自己的UI组件以及与用户自己的一组交互,因此在try / catch / finally块中“包装”我们与插件的交互是非常困难的。

是否有任何框架/编程库/模式可以解决这个问题?我们可以做插件很好; 我们需要帮助的是在不同AppDomain中的代码意外失败时保持应用程序处于活动状态。

5 个答案:

答案 0 :(得分:9)

您可以使用System.Addin框架(有时称为MAF),这对于正确设置有点麻烦,但它旨在提供隔离(崩溃保护)。 System.Addin基于远程处理。使用此框架,您可以让插件以有限的权限,在同一进程中运行,或在另一个应用程序域中运行,甚至在另一个进程中运行。

如果您需要完全防撞保护,则可能需要使用过程分离选项。但这可能会以性能为代价。

您可以使用此代码在其他应用程序域中加载插件:

AppDomain addInDomain = AppDomain.CreateDomain("addin domain");

// addInDomain.PermissionSet = ...
AddInEnvironment env = new AddInEnvironment(addInDomain);

// Activate the add-in
IHostView addinInstance = addinToken.Activate<IHostView>(env);

Console.WriteLine(addinInstance.DoSomething());

AppDomain.Unload(addInDomain);

如果要将插件加载到另一个进程中,请进行完全隔离:

AddInProcess process = new AddInProcess();
process.Start();

// Activate the add-in
IHostView addinInstance = addinToken.Activate<IHostView>(process, AddInSecurityLevel.Internet);

try 
{
    // use a catch block, prevent exceptions from the addin crashing the main app
    Console.WriteLine(addinInstance.DoSomething());
} 
catch (Exception e)
{
    Console.WriteLine(e);
}

process.Shutdown();

这个blog给出了很好的描述。

可以将System.Addin与MEF结合使用,这些是免费的工具包,请参阅this article

请注意,System.Addin模型可能提供崩溃保护,您仍然需要处理插件代码中的减速或死锁。异步使用在这里会有所帮助。

答案 1 :(得分:1)

听起来你想要类似于OSGi for Java的东西 - Is MEF OSGi for .NET?看起来可能符合这个要求。

答案 2 :(得分:1)

答案 3 :(得分:1)

我不认为这是可能的。我的理解是,即使您处理AppDomain.UnhandledException事件,应用程序仍将终止。您可以做的最好的事情是处理异常,记录您可以使用的内容,保存您可以使用的状态,并优雅地终止。

答案 4 :(得分:0)

我认为您已经检查了文档,但如果不是以下页面

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

确实提供了有关未处理异常如何工作的大量信息。它还提到了几个 允许微调行为的属性。

不幸的是,由于我没有以这种方式使用单独的AppDomain,因此无法向您提供有关您具体情况的任何提示。我可以说的是,根据我对UnandledException事件的经验,IsTerminating标志很少是真的,我们几乎总能从未处理的异常中恢复。