在运行时动态加载程序集依赖项时出现问题

4
让我试着解释一下我的问题。我目前正在尝试开发一个写在.Net中的小型“插件框架”(主要是为了进行一些实验)。因此,想法是有一个主应用程序,可以通过在特定文件夹“插件”中部署dll来添加“插件”。 一切都很顺利,插件被正确实例化,但现在我面临一个问题。 我现在部署了一个名为“X”的插件,它使用额外的第三方插件,所以现在我遇到的问题是这些由“X”所需的额外的第三方插件在运行时找不到。因此,我的想法是添加一个额外的目录“依赖项”,在那里我也部署所有需要的插件。
因此,我的第一个问题是: 如何将程序集加载到应用程序域中(假设我知道它们的路径),以便它们可以被我的应用程序使用?
我试图通过以下方式解决这个问题:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    //find the path to the assembly and then load and return it by
    //return Assembly.Load("pathToDependencies/failedAssembly.dll");
}

问题在于这个事件处理程序现在被激活并且在"args"变量中有"Presentation.Zune.dll"(我正在使用WPF应用程序)。它似乎加载失败了,但实际问题是另一个dll。有人能建议一种更好的解决方法吗?希望我已经足够清楚地解释了我的情况,否则请进一步说明。谢谢,Juri
3个回答

9
你可以设置运行时的探测路径,以便找到程序集。在应用程序配置文件中设置“probing”元素。请参考此链接
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="plugins;dependencies"/>
    </assemblyBinding>
  </runtime>
</configuration>

2

当框架尝试加载程序集并失败时,AssemblyResolve事件会发生。

这意味着如果它在参数中给出了Presentation.Zune.dll,那么框架找不到该程序集,而这是您拦截并执行其他操作的机会,例如从框架可能不知道的目录加载它 - 例如您的插件/依赖项文件夹...

我想到的方法是:

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if( File.Exists(".\\Plugins\\"+args.Name) )  // it's a plugin
        return Assembly.Load(".\\Plugins\\"+args.Name);
    else if( File.Exists(".\\Plugins\\Dependencies\\"+args.Name) )  // it's a dependency OF a plugin
        return Assembly.Load(".\\Plugins\\Dependencies\\"+args.Name);
    else
        throw new Exception();
}

这正确吗?我相信AssemblyResolve只在运行时无法解析程序集时才会被调用。 - Jakob Christensen

1

顺便说一下:如果您在字典中缓存已经解析的程序集,可以大大加快程序集的加载速度。如果 A 依赖于 B、C,而 B 又依赖于 C,当您加载 A 时,AssemblyResolve 将会两次调用 C,只加载一次程序集会更快 :)

(我不确定 AssemblyResolve 是否总是被调用多次,但我在调试项目时注意到了这一点。而且缓存程序集也不会有什么坏处...)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接