问题描述
我们有一个应用程序,作为其要求之一,它将采用任意的 3rd 方插件,加载它们,并与我们自己开发的应用程序一起运行它们的 UI.我们一直在将这些 3rd 方插件加载到他们自己的 AppDomains 中以进行隔离,并且一切正常.
We have an application which, as one of its requirements, will take arbitrary 3rd party plugins, load them, and run their UI alongside our home-grown application. We've been loading these 3rd party plugins into their own AppDomains for isolation purposes, and everything works ok.
直到其中一个插件因未处理的异常而崩溃.在这种情况下,整个应用程序都会关闭,即使真正受影响的是我们的额外"工具窗口之一.
Until one of the plugins crashes out with an unhandled exception. In this circumstance, the entire application goes down, even though all that is really affected is one of our 'extra' tool windows.
理想情况下,我们想要某种方式来处理未处理的"异常,卸载损坏的 AppDomain,然后重新加载它. 问题是我们找不到机制在未处理异常的事件处理程序中,我们可以将异常标记为已处理".此外,由于插件有自己的 UI 组件以及它们自己与用户的交互集,因此将我们与插件的交互包装"在 try/catch/finally 块中将非常困难.
We'd like, ideally, some way to handle the "unhandled" exception, unload the damaged AppDomain, and then just reload it fresh. The problem is that we can't find a mechanism in the event handler for the unhandled exception whereby we can flag the exception as being 'handled'. Further, since the plugins have their own UI components with their own set of interactions with the user, it would be extremely difficult to "wrap" our interactions with the plugins in try/catch/finally blocks.
是否有任何框架/编程库/模式可以解决这个问题?我们可以很好地做插件;我们需要帮助的是在不同 AppDomain 中的代码意外失败时保持应用程序活动.
Are there any frameworks/programming libraries/patterns that lend themselves to solving this problem? We can do plugin stuff fine; what we need help with is keeping the application alive when code in a different AppDomain fails unexpectedly.
推荐答案
可以使用System.Addin
框架(有时也称为MAF
),有点正确设置很麻烦,但旨在提供隔离(碰撞保护).System.Addin
基于远程处理.使用此框架,您可以让插件以有限的权限在同一个进程、另一个应用程序域甚至另一个进程中运行.
You can use the System.Addin
framework (sometimes known as MAF
), which is a bit of a hassle to set up correctly, but which was designed to provide isolation (crash protection). System.Addin
is based on remoting. With this framework you can let plugins run with limited permissions, in the same process, or in another app-domain, or even in another process.
如果您需要全面的崩溃保护,您可能需要使用进程分离选项.不过,这可能会以牺牲性能为代价.
If you need total crash protection you may need to use the process separation option. It may come at the cost of performance though.
您可以使用此代码在不同的应用域中加载插件:
You can use this code to load an addin in a different app domain:
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);
如果要将插件加载到另一个进程中,以实现完全隔离:
If you want to load the addin into another process, for complete isolation:
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();
这个博客 很好地说明了如何设置.
This blog gives a good description of setting this up.
可以将 System.Addin
与 MEF 结合使用,这些是免费的工具包,请参阅 这篇文章.
It is possible to combine System.Addin
with MEF, these are complimentary toolkits, see this article.
请注意,System.Addin 模型可能提供崩溃保护,您仍然需要处理插件代码中的减速或死锁.异步使用在这里会有所帮助.
Note that the System.Addin model may provide crash protection, you will still need to deal with slowdowns or deadlocks in the addin code. Asynchronous usage will help here.
这篇关于强大的插件/插件管理的良好架构/库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!