Nuget DLL Hell:无法加载文件或程序集 System.Runtime

Zoo*_*oop 3 .net c# asp.net nuget

今天将 Application Insights 升级到最新版本后,由于我们的站点不再报告调用堆栈,我们的 .NET Framework 4.6.1 ASP.NET 站点现在在初始化时崩溃,原因如下:

System.IO.FileLoadException: 'Could not load file or assembly 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)'
Run Code Online (Sandbox Code Playgroud)

过去我曾为另一份工作解决过一个非常相似的问题。主要区别在于该问题是由 .NET Core 或 Standard 中的 Nuget 包引起的。因此,有多个同名的 .NET DLL 被复制到 bin 文件夹(在这种情况下为 System.Net.Http)。在那种情况下,它就像不再更新那个 Nuget 包一样“容易”......

虽然我认为这里的情况略有不同,但“不升级”不再是一种选择。Application Insights 不再报告调用堆栈有点违背了整个事情的目的!

因为它是 System.Runtime,而不是 Nuget 包,所以在配置文件中没有依赖版本标记;尽管即使那样也会奏效,但这似乎是一个临时解决方案。

我的理论是,现在项目中某个地方可能隐藏了 .NET Core 的 .NET Standard,但我没有看到 NetStandard 参考,我不知道如何判断 Core 是否以某种方式被拖入。我还没有很高兴 (?) 与 Standard 或 Core 一起工作,但我还没有想到更多。我会继续谷歌搜索...

我认为这是因为我们有一个 .NET 3.5 DLL(除了 vanilla .NET Framework 3.5 的 System、System.Runtime.Serialization 和 System.Xml 之外,还有零 Nuget 或 DLL 引用),被 ASP.NET 项目引用,虽然这在以前从来不是问题。

我完全被难住了,当天停止了所有的开发。我一直在升级和降级各种软件包,查看它们的先决条件,但我没有找到任何提示。

Zoo*_*oop 6

两个不同的 Nuget 想要引入不同版本的 System.Runtime.dll。这在使用使用 .NET Standard 的 Nuget 的 .NET 项目中极为常见。这是我第二次遇到这个源于 System.Net.Http 的问题,因为几乎所有人都在使用它。

由于 System.Runtime 是一个 .NET Framework DLL,因此Program Files\Reference Assemblies无论您在 Visual Studio 或 CSProj 中做什么,Visual Studio 都会始终从文件夹中获取它。

就我而言,无论出于何种原因,复制到 bin 文件夹的版本是所需 DLL 的仅反射版本,这意味着我不能简单地使用<dependantAssembly>标签来强制它使用 bin 文件夹中的版本。我必须首先将 System.Runtime.dll 的完整版本放入 bin 文件夹。

除了更新到 .NET Core 之外,我唯一的想法(并由另一个 Stack Overflow 用户确认)是在后期构建中手动复制它。这很糟糕,但它适用于您拥有的任何冲突的 DLL:

  1. 由于 Nuget 包,您的项目引用中可能会有冲突的 DLL。我的问题更难,因为虽然 System.Runtime 是我使用的另一个 Nuget 的先决条件,但我猜是因为它是 .NET Framework 的一部分,它没有作为 Nuget 包或参考添加。如果没有,请自行拉取 Nuget 包。
  2. 在包文件夹中查找 DLL 的路径。例如,我的是$(SolutionDir)packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll。你会想用$(SolutionDir)宏交换你的解决方案目录,就像我所做的那样。
  3. 在项目的解决方案属性中编辑构建后事件命令行:

    copy "$(SolutionDir)packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll" "$(TargetDir)System.Runtime.dll"

  4. 在可以看到其版本号和公钥令牌的东西中打开 DLL,例如 ILSpy。在我的例子中,DLL 是版本 4.1.1.1,带有公钥令牌 b03f5f7f11d50a3a。请注意,在文件资源管理器中查看 DLL 的属性不会显示正确的版本号。

  5. 在文本编辑器中打开您的 app.config/web.config。如果<dependentAssembly>标签中还没有DLL 的configuration\runtime\assemblyBinding标签,请添加它。它应该是这样的:

<dependentAssembly> <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/> <bindingRedirect oldVersion="0.0.0.0-9.9.9.9" newVersion="4.1.1.1"/> </dependentAssembly>

  1. (续)用不带 .DLL 扩展名的 DLL 文件名替换名称。用您在 ILSpy 中发现的值替换公钥令牌。将 oldVersion 设置为一个广泛的范围。将 newVersion 设置为您在 ILSpy 中找到的版本。
  2. 每当您在 Nuget 包管理器中触摸该 nuget 包时,它可能会更改您的<dependentAssembly>标签!所以,在你的项目上留下一个文本文件、一个便利贴、一个霓虹灯标志,说如果你曾经弄乱过那个 Nuget 包,你可能需要编辑 post-build 和 app.config/web.config。
  3. 哭。

如果你像我一样坚持使用 .NET Framework,你可能最终不得不对许多 DLL 进行这种 hack,因为 .NET Standard/Core 变得更加普遍,因此更多的 DLL 最终与它们的 .NET 同名框架对应。我们发现将此解决方案部署到 Azure 上不起作用。

否则,唯一的其他解决方案是完全避免它:一次只升级一个 Nuget 包,并在每次之后彻底测试。Nuget 可以像俄罗斯轮盘赌 ;-)。尽管上述方法对我们有用,但我们最终回滚并缓慢而痛苦地升级,直到找到罪魁祸首。

如果你知道更好的方法,我很想听听。

  • 从 web.config 中删除所有依赖于 .NET Framework 的绑定Assembly bindingRedirects 对我有用,根本不需要将 dll 放在 bin 中 (2认同)