插件 AppDomains 解决方法

Posted

技术标签:

【中文标题】插件 AppDomains 解决方法【英文标题】:Plugin AppDomains Workaround 【发布时间】:2012-06-06 23:28:10 【问题描述】:

在处理它们自己的子目录中的插件程序集时,有一个众所周知的问题,即这些程序集一旦尝试从其子目录中加载各自的依赖项,就会无法加载。一种解决方案是在 AppDomains 中加载插件,这些插件在初始化时将其 PrivateBinPath 设置在其 AppDomainSetup 对象中。但是,这会导致有关编组/跨 AppDomain 通信的其他困难,特别是如果插件应该提供一些 GUI。

当安全方面的优先级较低(非关键实用程序应用程序,由于错误插件导致崩溃时没有严重问题),我有以下想法:在应用程序启动时,应搜索所有插件目录,并且应该创建一个新的 AppDomain,在其 bin 路径中包含这些目录。然后,整个应用程序及其 GUI 与所有插件一起在新的 AppDomain 中运行。

在给定的情况下,是否有任何理由避免该解决方案?或者是否有任何原因导致该解决方案甚至不可行?

【问题讨论】:

我认为如果你的主 UI 和插件在同一个 AppDomain 中运行,如果插件崩溃,主 UI 很可能会崩溃。您使用的是插件框架还是“RYO”? @IAbstract:即使在另一个 AppDomain 中运行,插件崩溃通常不会导致主 UI 崩溃吗?毕竟,插件中抛出的任何异常都会跨 AppDomain 边界进行编组,并使主应用程序退出,除非我处理异常。在我的特殊情况下,这是 RYO - 我已经研究了 Addin Framework 并阅读了许多关于它的文章,但它们都提到了核心应用程序和插件之间相当简约的接口,而不是我将要介绍的复杂和深度嵌套的对象层次结构需要转移。 【参考方案1】:

考虑到您描述的场景,我不知道与您的第二个域提案相关的任何问题。但是,您也可以通过搜索自己的插件子目录并使用Assembly.LoadFrom 从那里加载程序集来研究在初始域上处理程序集加载失败的可能性。

可能的设置示例,其中必须实现 FindAssemblyByName 以搜索所有可能的位置:

static void Main(string[] args)

    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

    // ...


static Assembly CurrentDomain_AssemblyResolve(
    object sender, 
    ResolveEventArgs e)

    var assemblyName = new AssemblyName(e.Name);

    string assemblyFilePath = FindAssemblyByName(assemblyName);

    if (string.IsNullOrEmpty(assemblyFilePath))
        return null;

    return Assembly.LoadFrom(assemblyFilePath);

【讨论】:

这仅适用于托管程序集吗?更具体地说,当我在子目录中手动找到插件程序集时,是否会自动发现同一子目录中的非托管库? Assembly.LoadFrom 允许找到并加载对该路径的进一步依赖,因为路径信息由上下文维护。但是,由于混合了非托管程序集,我不愿意给你任何确定性。 我已经进一步阅读并做了一些测试。如果它们与使用LoadFrom 加载的程序集位于同一目录中,那么似乎不仅可以找到托管库,而且还可以找到非托管库。但是,阅读docs,似乎LoadFrom 专门将程序集加载到所谓的 load-from 上下文中,而 load 上下文对于很多原因。另一方面,我看不到任何方法可以将程序集从自定义位置加载到该 load 上下文中。

以上是关于插件 AppDomains 解决方法的主要内容,如果未能解决你的问题,请参考以下文章

具有插件和多租户支持的 ASP.NET MVC 应用程序以及单独的 AppDomains?

从 AppDomain 解决 InvalidOperationException

Thread.Abort()方法冻结

限制插件汇编代码访问

AppDomains之间的通信

csdn插件“安装失败, 请将插件更新至最新版本“的解决方法