GWL*_*osa 7 .net architecture error-handling plugins crash-recovery
我们有一个应用程序,作为其要求之一,它将采用任意第三方插件,加载它们,并在我们自己开发的应用程序旁边运行它们的UI.我们一直在将这些第三方插件加载到他们自己的AppDomain中以实现隔离,一切正常.
直到其中一个插件因未处理的异常而崩溃.在这种情况下,整个应用程序都会关闭,即使所有真正受到影响的应用程序都是我们的"额外"工具窗口之一.
理想情况下,我们想要一些方法来处理"未处理"的异常,卸载损坏的AppDomain,然后重新加载它. 问题是我们无法在事件处理程序中找到未处理异常的机制,我们可以将异常标记为"已处理".此外,由于插件具有自己的UI组件以及与用户自己的一组交互,因此在try/catch/finally块中"包装"我们与插件的交互是非常困难的.
是否有任何框架/编程库/模式可以解决这个问题?我们可以做插件很好; 我们需要帮助的是在不同AppDomain中的代码意外失败时保持应用程序活跃.
您可以使用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);
Run Code Online (Sandbox Code Playgroud)
如果要将插件加载到另一个进程中,则需要完全隔离:
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();
Run Code Online (Sandbox Code Playgroud)
这个博客给出了很好的描述.
可以System.Addin与MEF 结合使用,这些是免费的工具包,请参阅此文章.
请注意,System.Addin模型可能提供崩溃保护,您仍然需要处理插件代码中的减速或死锁.异步使用在这里会有所帮助.