为什么我的.NET Standard NuGet包会触发这么多依赖项?

问题描述 投票:37回答:2

我一直在和a .NET Standard project和NuGet杂乱无章。我有一个工作项目,并有uploaded it to NuGet.org。我的项目面向.NET Standard 1.3,其中包括should support .NET Framework 4.6和.NET Core 1.0。

但是当我尝试将我的项目(通过NuGet)添加到一个新的.NET Framework 4.6项目时,依赖关系解析为47个包!它们都是系统库,似乎是Microsoft.NETCore.Platforms或NETStandard.Library 1.6.1的依赖项。 (Gist of full PM output.

我的项目只导入(using)一些库,我没有手动添加;即它们都是“随.NET标准附带”的库。这些库是:

  1. 系统
  2. System.Text
  3. 的System.Reflection
  4. System.Linq的
  5. System.Collections.Generic;

问题是,我决定让我的项目成为.NET Standard,因为我希望它能够跨.NET Framework和.NET Core应用程序无缝地工作。我认为标准的重点是设置最低级别的兼容性。通过扩展,我想我曾(或许是错误地)假设像System.Console这样的库可以在Core或Framework中自动使用。

当我在同一个解决方案中测试我的Standard项目作为Framework和Core项目中的依赖项时,我没有注意到这样的事情,所以我怀疑这可能是一个NuGet的事情。

这里到底发生了什么?如何在没有大量依赖项的情况下在NuGet上提供我的.NET标准库?

这是我指定我的NuGet包的方式有问题吗?或者我从根本上误解了什么?

.net nuget .net-standard
2个回答
42
投票

你没有做错任何事,预计会发生这种情况。如果您只想将自己的DLL添加到新的.NET Framework项目中,则必须为您的库定位.NET Standard 2.0,等待本机支持API和汇编版本的.NET Framework版本 - 这将是为4.7.2(虽然.NET Framework 4.7.1支持所有API,但有一些程序集的版本化存在错误,因此工具(VS 2017 15.5+)将添加其他程序集来修复它)。

您所看到的是.NET Standard的构建方式以及对支持的框架的支持的副作用。根据您定位的.NET Standard版本和用于引用库包的工具,这也有所不同。

在.NET Standard <2.0中,您引用了NETStandard.Library元数据包,后者又引用了其他(System.*)包。这些包包含构成“.NET标准合同”的引用程序集 - 一组API和程序集名称+版本。

当您为.NET Standard 1.0-1.6创建的NuGet包随后被应用程序引用时,这些单独的包不会引入引用程序集,而是引入应用程序所针对的框架的实现程序集。

对于.NET Core,它们匹配已经是运行时的一部分的程序集,因此DLL文件不会在构建的应用程序旁边结束。但是,当为.NET Core 1.1(NETStandard.Library版本1.6.1)发布一组新的软件包时,这一情况发生了变化。这导致为.NET Core 1.0构建的应用程序最终获得了旨在包含在.NET Core 1.1中的更新的实现程序集(幸运的是,1.1因此成为“长期支持”版本,因为这引发了关于哪些程序集的讨论是LTS承诺的一部分)。

在.NET Framework上,这些库(有一些例外情况,如System.Net.Http)没有做太多 - 它们只是转发到系统程序集。因此,例如“契约”定义System.ObjectSystem.Runtime.dll集合中定义。因此,您在.NET Framework应用程序中最终得到的System.Runtime.dll文件包含一个System.Runtime.dll,其中包含类型转发到.NET Framework的mscorlib.dll。 .NET Core已经包含了一个不同的System.Runtime.dll,它为该平台做了不同的事情。这种机制允许单个DLL文件在两个平台上工作,因为这些类型转发和其他实现确保在两个实现上工作的相同“契约”(类型+程序集+汇编版本)。

.NET Standard 2.0旨在减少必需的包和DLL的数量,并且每当发布新的.NET Core版本时,都要删除对NETStandard.Library的更新。

因此,对于.NET Standard 2.0和.NET Core 2.0,NETStandard.Library包只会将用于编译代码的引用程序集带到项目中,但生成的NuGet程序包不再依赖于此程序包。因此,当您创建一个面向.NET Standard 2.0并发布它的库时,它将没有NuGet依赖项(除非您添加其他的)。

在使用.NET标准库时,“支持库”引入的逻辑被移动到构建期间使用的工具。因此,当包含对netstandard.dll的引用的库添加到.NET Framework项目中时,该工具将根据所使用的.NET Framework版本添加必要的支持DLL。这是针对.NET Standard 2.0以及.NET Standard 1.5+完成的,因为.NET Framework 4.6.1通过这些类型的DLL文件追溯性地与.NET Standard 2.0(先前为1.4)兼容。相同的工具也确保即使NuGet包以某种方式引入这样的应用程序项目,从构建中删除通过NuGet引入的任何.NET标准实现库。因此,如果您引用.NET Core 1.0发布时构建的.NET Standard 1.0 NuGet包,则会修剪其所有NuGet依赖项,并获得构建工具附带的支持库。

这个想法是.NET Framework 4.7.1将包含所有必要的程序集“inbox”,因此netstandard.dllSystem.Runtime.dll等是.NET Framework的一部分,任何.NET Standard 1.0-2.0 DLL文件都“正常工作”,问题是这些“收件箱”DLL文件的某些程序集的版本号太低,因此库无法加载 - 这是通过再次更改工具以包含具有更高版本号的DLL文件作为支持库来修复的,而这些文件又转发到支持库“收件箱”.NET Framework程序集。计划在.NET Framework 4.7.2中修复此问题。


3
投票

我也遇到了这个问题。您在对Martin Ullrich的回答中评论的blog post让我得到了一个对我有用的解决方案:使用NuGet multi-targeting。通过更改:

<TargetFramework>netstandard1.0</TargetFramework>

<TargetFrameworks>netstandard1.0;netstandard2.0;net45</TargetFrameworks>

在项目.csproj文件中。这会导致为每个目标框架单独构建项目,并且生成的NuGet包仅依赖于NETStandard.Librarynetstandard1.0。从NuGet chooses the net45 binaries for any full .NET Framework version开始,这可以避免在安装软件包时出现不必要的依赖关系。

© www.soinside.com 2019 - 2024. All rights reserved.