传递依赖导致相同 DLL 的版本冲突

Posted

技术标签:

【中文标题】传递依赖导致相同 DLL 的版本冲突【英文标题】:Transitive Dependency causing Conflicting version of same DLL 【发布时间】:2012-07-05 08:10:51 【问题描述】:

.NET 世界中管理导致版本冲突的传递依赖项的最佳实践是什么?

详情: 项目 A 依赖于项目 B,而项目 B 又依赖于库 C

还有

项目 A 还依赖于项目 X,项目 X 依赖于库 C 的不同且(可能)不兼容的版本。

A->B->Cv1.0 & A->X->Cv2.0 其中 Cv1.0 Cv2.0

有没有办法让这个工作?

可以在不使用 GAC 的情况下完成吗?

即使 B 和 X 只是二进制格式也能做到吗(来源不可访问)?

换句话说,有没有一种方法可以让项目 B 和 X 在项目 A 中一起使用时各自使用自己的依赖项而不会引起冲突。

注意:我意识到理想情况下我根本不应该有这个问题,但是随着对外部库的依赖扩大,这将是一个不可避免的副作用。所以我想知道它应该如何最好地处理它。

【问题讨论】:

理想情况下,您应该重新构建或更新 B,使其依赖于当前版本的 C。如果您不能这样做,您可以尝试重新映射版本。 ***.com/a/11126867/48082这不保证有效! 同意理想情况下应该清理他们的项目以避免在第一时间出现这种情况,但这并不总是可能的,因此问题。 仅当两个版本相互兼容时,以某种方式重新映射 DLL 才是好的。这里最糟糕的情况是,如果它们不兼容,是否有办法让每个中间依赖项使用它所针对的版本,并且仍然执行主项目期望它们完成的工作。 是的,您还可以加载程序集的多个不同版本。为此,请使用不同的 AppDomain。 ***.com/a/1189491/48082 CLR 可以在 AppDomain 中加载 2 个版本(我已经观察到这一事实,我想通过强命名引用就足够了)。但是,如果不重构/重新编译外部依赖项,您就会面临很多麻烦。适用于您机器的解决方案可能不适用于其他奇异的生产环境。 【参考方案1】:

在 Stack Overflow 上有很多类似的问题。 例如Referencing 2 different versions of log4net in the same solution

总结:

    确保将程序集 C 分别部署在包含主可执行文件的文件夹中的文件夹 1.0 和 2.0 中。 更改 app.config 文件并包含以下内容:
 <configuration>
   <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
       <assemblyIdentity name="C" publicKeyToken="C's public key token" />
        <codeBase version="version string for C1.0 e.g. 1.0.0.0" href="1.0\C.dll" />
        <codeBase version="version string for C2.0 e.g. 2.0.0.0" href="2.0\C.dll" />
       </assemblyIdentity>
      </dependentAssembly>
    </assemblyBinding>
   </runtime>
 </configuration>

您可以使用 sn -T C.dll 获取 C 的公钥令牌

如果 C 的 v1.0 和 v2.0 具有不同的公钥(尽管理想情况下它们不应该),则包含两个dependentAssembly 标记。

【讨论】:

确实有很多问题,但没有一个真正回答我的问题。我对 assemblyBinding 的理解是它允许指定哪个 DLL 用于哪个命名空间并相应地重定向调用。这里每个调用路径最终将针对单个 DLL。在我公开的场景中,我们有两个相同的调用路径,它们必须针对两个不同的 DLL。唯一的区别是每个都是从不同的“父”DLL 调用的。除非我没有正确理解 assemblyBinding 的目的。 Tha 说我猜如果两个依赖项(上例中的 B 和 X)的发布者在生成他们的库时专门硬连接 DLL 依赖项(上面的 C)版本,那么一切都会正常工作(前提是两个 C Dll 都是唯一可识别的文件,即不同的名称和/或路径)。我将不得不对 assemblyBinding 进行一些试验,看看能做什么 如果 C 是强命名的,上面应该可以工作并且应该能够为 B 和 X 加载正确的 C 版本。如果它不是强命名但仍然有一个版本(通过 AssemblyVersion 属性指定)然后您可以尝试删除 publicKeyToken 并查看它是否仍然有效。如果这不起作用,我认为唯一的希望是 AssemblyResolve 事件。我将尝试检查所有这些如果和但是并分享结果。 感谢 Amit 在这方面付出的时间和精力,很想看看你会发现什么

以上是关于传递依赖导致相同 DLL 的版本冲突的主要内容,如果未能解决你的问题,请参考以下文章

Android Gradle 插件Android 依赖管理 ⑤ ( Gradle 依赖优化 | 命令行查看依赖模块 | 依赖冲突问题 | 依赖传递冲突 | 分库冲突 | 依赖分组不同导致冲突 )

是否有一个 Maven 插件可以验证传递依赖项的冲突版本?

8.依赖的传递排除冲突

版本冲突与Project DevExpress相同

C#依赖的DLL版本冲突的问题

maven-传递依赖和依赖冲突版本解决