在运行时加载 2 个版本的程序集

Posted

技术标签:

【中文标题】在运行时加载 2 个版本的程序集【英文标题】:Loading 2 versions of assembly at runtime 【发布时间】:2009-07-27 17:01:25 【问题描述】:

过去几周我一直在尝试破解这个问题,但还没有找到好的解决方案;希望我能在这里得到答案。

我有两个程序集(ZA 和 ZB),它们都指向一个公共项目/dll (ZC),但它们可能位于不同的版本上(即相同的 dll 名称、相同的命名空间、某些类可能不同)。每个程序集自行工作,但是,如果一个程序集在运行时由另一个程序集加载(例如 A 加载 B),那么我无法让它工作。需要一些帮助。

设置如下:

ZA 依赖于 ZC(通用)1.1 版 ZB 依赖于 ZC 1.0 版

ZA需要加载需要在ZB中加载一些东西(这取决于ZC),在运行时。

ZA 是主应用程序。 在其bin 目录下,有一个插件目录plugins/plugin-ZB,我想在其下放置所有 ZB 及其依赖项 (ZC)。

这是我迄今为止尝试过的:

Assembly.Load() 使用相同版本的 dll - 工作正常。

Assembly.Load() 使用不同版本的 dll - ZB 加载,但是当方法运行时,我得到一个方法未找到异常。

AppDomain.Load() got a file not found 错误;我什至使用委托来解析程序集。

关于ZC的一些细节: - 有些方法是公共静态的(有些不是)。例如。 Log.Log("hello"); - 有些可能返回值(基元或对象)。 - 一些方法是非静态的(和返回值)。

帮助? - TIA

【问题讨论】:

【参考方案1】:
    m_Assembly1 = Reflection.Assembly.LoadFile(IO.Path.Combine(System.Environment.CurrentDirectory, "Old Version\Some.dll"))
    m_Assembly2 = Reflection.Assembly.LoadFile(IO.Path.Combine(System.Environment.CurrentDirectory, "New Version\Some.dll"))

    Console.WriteLine("Old Version: " & m_Assembly1.GetName.Version.ToString)
    Console.WriteLine("New Version: " & m_Assembly2.GetName.Version.ToString)

    m_OldObject = m_Assembly1.CreateInstance("FullClassName")
    m_NewObject = m_Assembly2.CreateInstance("FullClassName")

从现在开始,我使用后期绑定和/或反射来运行我的测试。

.NET: Load two version of the same DLL

【讨论】:

很好的建议!不知道【参考方案2】:

除了 Jonathan Allen 的出色建议之外,解决问题的更“经典”方法是在 2 个不同的 AppDomanis 中加载 2 个版本。然后,您可以使用 .NET Remoting 使两个 AppDomain 进行通信。所以ZA应该创建一个新的Appdomain,在这个AppDomain ZB中加载并通过Remoting在ZB中调用一些操作。

请注意,.NET Remoting 对您要使用的类有一些要求(从 MarshalByRef 继承),并且创建 AppDomain 是一项昂贵的操作。

希望有帮助

【讨论】:

“AppDomain 只能有一个程序集版本”不正确。甚至可以从一个程序集引用一个程序集的两个版本,查找外部别名以获取更多信息,这是在 Google 上弹出的第一件事,其中包含该功能的示例:blogs.msdn.com/b/ansonh/archive/2006/09/28/… 使用两个 AppDomain 可以解决上述问题。【参考方案3】:

我同时加载了同一个程序集的两个版本。正如你所描述的那样,它发生在一个场景中。

您必须说服运行时为 ZA 和 ZB 加载相同版本的 ZC。我找到了两种方法:

    在 App.config 文件中使用 bindingRedirect 元素。 this question有一些细节。 使用AppDomain.AssemblyResolve 事件。 this answer有一些细节。

AppDomain.AssemblyResolve 的唯一问题是它仅在运行时找不到请求的版本时触发。如果两个版本都可用,那么您必须使用bindingRedirect。我使用了AppDomain.AssemblyResolve 事件,然后添加了一个安全检查,以确保通过查看程序集的引用程序集集合来加载正确的版本。如果不是,我会向用户抱怨该库的旧版本存在并告诉他们它在哪里。

【讨论】:

这不是加载两个不同的版本,而是加载相同的版本两次。 当我遇到这个问题时,@Cameron,当 ZA 启动时,运行时加载了 ZC 的 1.1 版。然后当我加载ZB插件时,运行时加载了ZC 1.0版本。这就是我加载两个不同版本的意思。为了让 ZA 和 ZB 将对象从 ZC 传递给对方,我必须让它们都加载相同版本的 ZC。这就是我在回答中描述的方法。我误解了原来的问题吗?

以上是关于在运行时加载 2 个版本的程序集的主要内容,如果未能解决你的问题,请参考以下文章

运行时无法加载文件或程序集“Newtonsoft.Json,版本=6.0.0.0 ...”,间接依赖程序集继续寻找旧版本

抛出:当我运行我的应用程序版本 .exe 时,“无法加载文件或程序集错误”

C#动态加载dll 时程序集的卸载问题

混合模式程序集是针对运行时的“v2.0.50727”版本构建的,无法在 4.0 运行时中加载 - 研究的解决方案不起作用

混合模式程序集是针对运行时的“v2.0.50727”版本构建的

ASP.NET运行时错误:未能加载文件或程序集或它的某一依赖项.参数错误.