我们有一个应用程序,作为其要求之一,它将采用任意 3rd 方插件,加载它们,并与我们自己开发的应用程序一起运行它们的 UI。我们一直在将这些 3rd 方插件加载到他们自己的 AppDomains 中以进行隔离,并且一切正常。
直到其中一个插件因未处理的异常而崩溃。在这种情况下,整个应用程序都会关闭,即使真正受影响的是我们的“额外”工具窗口之一。
理想情况下,我们想要某种方法来处理“未处理”异常,卸载损坏的 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);
如果要将插件加载到另一个进程中,以实现完全隔离:
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 模型可能提供崩溃保护,您仍需要处理加载项代码中的减速或死锁。异步使用在这里会有所帮助。
关于.net - 强大的插件/插件管理的良好架构/库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5494258/