c# - Nuget DLL hell : Could not load file or assembly System. 运行时

标签 c# asp.net .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)'

过去我曾为另一份工作解决过非常相似的问题。主要区别在于该问题是由 .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 项目引用,虽然这在以前从来都不是问题。

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

最佳答案

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

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

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

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

  • 由于 Nuget 包,您的项目引用中可能会有冲突的 DLL。我的问题更难,因为虽然 System.Runtime 是我使用的另一个 Nuget 的先决条件,但我猜是因为它是 .NET Framework 的一部分,它没有作为 Nuget 包或引用添加。如果没有,请自行拉取 Nuget 包。
  • 在包文件夹中查找 DLL 的路径。例如,我的是 $(SolutionDir)packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll 。你会想用 $(SolutionDir) 宏交换你的解决方案目录,就像我所做的那样。
  • 在项目的解决方案属性中编辑构建后事件命令行:
    copy "$(SolutionDir)packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll" "$(TargetDir)System.Runtime.dll"
  • 在可以看到其版本号和公钥标记的东西中打开 DLL,例如 ILSpy。就我而言,DLL 的版本为 4.1.1.1,带有公钥 token b03f5f7f11d50a3a。请注意,在文件资源管理器中查看 DLL 的属性不会显示正确的版本号。
  • 在文本编辑器中打开您的 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>
  • (续) 用不带 .DLL 扩展名的 DLL 文件名替换名称。用您在 ILSpy 中发现的值替换公钥 token 。将 oldVersion 设置为广泛的范围。将 newVersion 设置为您在 ILSpy 中找到的版本。
  • 每当您在 Nuget 包管理器中触摸该 nuget 包时,它可能会更改您的 <dependentAssembly> 标记!所以,在你的项目上留下一个文本文件、一个便签、一个 NEON 标志,说如果你曾经弄乱过那个 Nuget 包,你可能需要编辑 post-build 和 app.config/web.config。
  • 哭了。

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

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

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

    关于c# - Nuget DLL hell : Could not load file or assembly System. 运行时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57236119/

    相关文章:

    c# - 我们可以将对象数据源控件分配给数据集吗?

    c# - 让业务逻辑对象提示用户输入是不是糟糕的设计?

    .net - F# 可以更新类中的不可变绑定(bind)(创建一个更改了指定绑定(bind)的新对象吗?)

    javascript - 对 web 方法的 Ajax 调用给出错误 500 内部服务器错误

    c# - 如何获取项目之间共享的app.settings文件的相对文件路径

    c# - 从 C# 背后的代码访问 HTML 控件

    c# - 任务异常管理c#

    c# - 为什么对具有两个命名属性的对象列表使用字典?

    c# - 从容器中取出零件时的处理

    c# - 如何从对象列表中删除重复项?