无法在两个.NET Standard项目中合并NuGet包的传递依赖版本

13

将 EF Core 添加到 NET Standard 项目中会引入与其他项目中 NuGet 包不兼容的传递依赖项版本

我有一个包含多个 .NET Standard 2.0 项目的解决方案。

项目 A 使用 Google.Protobuf (3.11.2) NuGet 包,该包具有以下依赖关系:

System.Memory (4.5.3)
    System.Buffers (4.4.0)
    System.Numerics.Vectors (4.4.0)
    System.Runtime.CompilerServices.Unsafe (4.5.2)

还有几个其他项目依赖于 System.Memory,而且所有这些项目都使用相同的依赖版本

另一个B 项目使用 Microsoft.EntityFrameworkCore (3.1.0) NuGet 包,该包也是依赖于

System.Memory (4.5.3)
    System.Buffers (4.5.0)
    System.Numerics.Vectors (4.5.0)
    System.Runtime.CompilerServices.Unsafe (4.7.0)
即使System.Memory版本在两种情况下都是(4.5.3),但它依赖于System.BuffersSystem.Numerics.VectorsSystem.Runtime.CompilerServices.Unsafe,它们的版本不同。
当运行使用这些项目的应用程序(使用Unity IoC的Microsoft Prism WPF .NET Framework 4.8应用程序)时,UnityContainer会抛出以下异常:

System.IO.FileLoadException:无法加载文件或程序集'System.Runtime.CompilerServices.Unsafe,Version=4.0.4.1,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a'或其其中一个依赖项。 找到的程序集清单定义与程序集引用不匹配。

在寻找解决方案后,我将此添加到我的NuGet.Config:
  <config>
    <add key="DependencyVersion" value="Highest" />
  </config>

%appdata%\Nuget.sln文件的根目录中都需要进行操作。

我也删除了%userprofile%\.nuget\packages文件夹。

然后我从项目中删除了NuGet包,并将它们重新添加,但是它们的依赖关系与以前相同。

如果我在Visual Studio中导航到“管理解决方案的NuGet包”,并选择“合并”选项,它只会显示“未找到任何软件包”。


@PabloRecalde 是的,这正是我的意思。但我没有安装 System.Memory,所以我无法控制它的版本 - 它是作为 Google.ProtobufMicrosoft.EntityFrameworkCore 的依赖项安装的。 - Jinjinov
似乎微软在版本方面出了问题...这对我来说毫无意义。 - Pablo Recalde
作为一种解决方法,您可以尝试覆盖与.nuget缓存文件夹中其他文件不匹配的dll。 - Pablo Recalde
1
@panoskarajohn 我的 .net standard 项目不引用 .net core 包 - Microsoft.EntityFrameworkCore 是一个 .net standard 库 ;) 如果你不相信我,你可以很容易地在 3 分钟内重现我的问题 :) - Jinjinov
1
@Jinjinov 噢,那真遗憾。最后一个想法:https://blog.yaakov.online/automatically-generating-assembly-binding-redirects/ 我希望这个能帮到你,因为它特别提到了类库的问题。如果不能,抱歉我没能帮上忙,希望你尽快找到解决方案! :) - Heki
显示剩余7条评论
2个回答

15
我成功地重现了这个问题。 我创建了两个新的.net标准2.0项目类库。
在第一个项目中,我添加了EF Core。 在第二个项目中,我添加了Google protobuf。
它们都是你提到的相同版本。
对于EF core,我创建了一个新类,只是继承自DbContext。 对于Protobuf,我只是创建了一个空类,因为我不熟悉如何使用它。 然而,我仍然能够复制出问题。
然后,我创建了一个控制台应用程序.net框架4.7.2,引用了上述两个项目。
我在控制台应用程序中实例化了这两个类,并得到了"error System.IO.FileLoadException: 'Could not load file or assembly..."。
我是如何解决它的
我进入了所有三个项目,并将这一行添加到csproj中。 PackageReference 到属性组。
<PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>

之后我重新构建并运行,没有出现任何错误。

请告诉我你的结果。即使我的解决方案对你不起作用,我相信它是一个好的做法。

引用Oren的话。
“使用.NET Standard需要您使用PackageReference来消除‘大量包’的痛苦,并正确处理传递依赖关系。虽然您可以在没有PackageReference的情况下使用.NET Standard,但我不建议这样做。”

Hanselman也提到: “‘完整’框架项目使用较旧的.csproj格式,并默认使用package.config来管理依赖关系。新项目可以将包作为一级引用进行引用。因此,我们需要告诉此解决方案中的所有项目以“PackageReferences”方式管理和还原其包。”

这是我的来源。

https://www.hanselman.com/blog/ReferencingNETStandardAssembliesFromBothNETCoreAndNETFramework.aspx

https://oren.codes/2017/04/23/using-xamarin-forms-with-net-standard-vs-2017-edition/

根据github issues中Sommen提供的额外信息进行更新。

感谢Sommen提供这些额外信息。同时也要感谢Immo Landwerth在GitHub上提供的信息。

我将按照jinjinov的建议,提供已经存在于Github页面上的解决方法,以便完整性。

来自GitHub Issues

解决方法

常规 .NET Framework 项目

  1. 在根 .NET Framework 应用程序中启用automatic binding redirects
  2. 确保您的根应用程序项目不使用 packages.config,而是使用 PackageReference 来获取 NuGet 包:
    • 如果您当前没有 packages.config,只需添加 <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
    • 如果您当前有一个 packages.config,请将其转换为项目文件中的包引用。语法如下: <PackageReference Include="package-id" Version="package-version" />

ASP.NET网站和Web应用程序

  1. Web应用程序和网站不支持自动生成绑定重定向。为了解决绑定冲突,您需要双击错误列表中的警告,Visual Studio会将其添加到您的web.config文件中。
  2. 在Web应用程序项目中,您应该像上面提到的那样启用PackageReference。在网站中,您不能使用PackageReference,因为没有项目文件。在这种情况下,您需要安装所有NuGet包到您的网站,以便满足直接或间接项目引用所依赖的任何包。

单元测试项目

默认情况下,类库项目不会添加绑定重定向。这对于单元测试项目是有问题的,因为它们本质上就像应用程序。除了自动生成绑定重定向中所述的内容外,您还需要指定GenerateBindingRedirectsOutputType

<PropertyGroup>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

还有一个讨论部分提供更多信息 -> GitHub讨论


谢谢!我阅读了来自sommme的链接https://github.com/dotnet/announcements/issues/31,我发现您的解决方案适用于没有任何NuGet包的项目--在GitHub问题中查看Workarounds,第2点。--我假设您的控制台应用程序中没有包含任何包?如果您更新答案以包括所有解决方法,我将接受它,因为您在sommme之前编写了它 :) - Jinjinov
@Jinjinov 谢谢,我已经更新了答案以提供完整的信息。如果你觉得还有更多需要补充,请毫不犹豫地进行编辑和更新。 - panoskarajohn
1
谢谢你提到单元测试!我的类库在存在冲突的传递依赖时运行得很好,但是当我从测试项目运行测试时,却抛出了FileLoadException异常,尽管测试项目并没有引用NuGet包!我只在MyTests.csproj中添加了GenerateBindingRedirectsOutputType,而不需要AutoGenerateBindingRedirects。 - undefined

4

欢迎加入奋斗的行列。

如PanosKarajohn所指出的那样,使用packagereference而不是packages.config可以解决这个问题。不幸的是,该方法需要Vs2017或更高版本,对于我们中的一些人来说还没有实现。

其实问题在这里已经解释得很清楚了:https://github.com/dotnet/announcements/issues/31

你需要使用绑定重定向(binding redirects)将所有版本号重定向到最高的版本,然后祈祷所有组件能够良好地协同工作。

我在一个.net 4.6.1项目中使用Microsoft.aspnetcore.signalR包,也遇到了相同的问题。


我已经更新了我的答案,根据原帖的建议,加入了您提供的复杂性链接。 - panoskarajohn
1
是的。我实际上花了大约3天的时间来解决这个问题,特别是因为我们现在需要支持vs2015和vs2019。我有一个类库,运行一个脚本来创建一个{name}.exe.config文件,以便与所有绑定重定向一起使用。然后将其复制到可执行项目中(并祈祷所有版本都向后兼容)。希望我们能够在某个时候升级到.net std和core。祝贺你应得的赏金,希望我们从这次努力中学到了很多 :) - sommmen
谢谢。我确实学到了很多东西。请随意编辑我的答案并追加 :) - panoskarajohn

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