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

10

在.NET世界中,如何管理可能引起版本冲突的传递依赖关系是最佳实践?

具体而言:

项目A依赖于项目B,而项目B又依赖于库C。

同时,

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

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

  • 有方法可以使这个工作吗?

  • 能否在没有使用GAC的情况下完成?

  • 即使B和X仅以二进制格式存在(源代码不可访问),也能够完成吗?

换句话说,在Project A中,是否有一种方式可以使Project B和X各自使用其依赖项,而不会导致冲突。

注意:我意识到理想情况下根本不应该存在这个问题,但随着对外部库的依赖程度增加,这将是不可避免的副作用。因此,我想知道如果出现这种情况,最好的处理方法是什么。


1
理想情况下,您应该重新构建或更新B,使其依赖于当前版本的C。如果您无法这样做,可以尝试重新映射版本。但这并不能保证一定能够成功! - Cheeso
2
同意理想情况下应该清理项目以避免第一次出现这种情况,但这并非总是可能的,因此才会有这个问题。 - Newtopian
1
重新映射 DLL 只有在两个版本彼此兼容时才是好的。最糟糕的情况是,如果它们不兼容,是否有一种方法让每个中间依赖项使用它所制作的版本,并仍然执行主项目期望的工作。 - Newtopian
是的,您也可以加载多个不同版本的程序集。为此,请使用不同的AppDomains。https://dev59.com/fUjSa4cB1Zd3GeqPG556#1189491 - Cheeso
2
CLR可以在AppDomain中加载2个版本(我已经观察到这一点,我猜通过强命名引用就足够了)。但是,如果不重构/重新编译外部依赖项,您将自己暴露于许多困难的问题之中。在您的机器上可行的解决方案可能在其他奇特的生产环境中无法正常工作。 - Patrick from NDepend team
显示剩余3条评论
1个回答

5

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

摘要:

  1. 确保你将C程序集分别部署在包含主可执行文件的1.0和2.0文件夹中。
  2. 更改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标记。


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

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