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

Tom*_*ght 48 .net nuget .net-standard

我一直在讨论.NET Standard项目和NuGet.我有一个工作项目并已将其上传到NuGet.org.我的项目面向.NET Standard 1.3,它应该支持 .NET Framework 4.6和.NET Core 1.0.

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

我的项目只导入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包的方式有问题吗?或者我从根本上误解了什么?

Mar*_*ich 56

你没有做错任何事,预计会发生这种情况.如果您只想将自己的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元包,后者又引用了additional(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程序集中定义的.因此,System.Runtime.dll您在.NET Framework应用程序中最终得到的文件包含一个System.Runtime.dll包含转发到.NET Framework的类型mscorlib.dll..NET Core已经包含了一个与System.Runtime.dll该平台不同的东西.这种机制允许单个DLL文件在两个平台上工作,因为这些类型转发和其他实现确保在两个实现上工作的相同"契约"(类型+程序集+汇编版本).

.NET Standard 2.0旨在减少必需的包和DLL的数量,并且还可以NETStandard.Library在发布新的.NET Core版本时删除需要更新的内容.

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

在使用.NET标准库时,"支持库"引入的逻辑被移动到构建期间使用的工具.因此,当包含对a的引用的库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框架4.7.1将包含所有必需的组件"收件箱",使一个netstandard.dll,System.Runtime.dll等是.NET Framework和任何.NET标准1.0-2.0 DLL文件将"只是工作"的一部分,问题是这些"收件箱"DLL文件的某些程序集的版本号太低,因此库无法加载 - 这是通过再次更改工具以包含具有更高版本号的DLL文件作为支持库来修复的,而这些文件又转发到"收件箱" ".NET Framework程序集.计划在.NET Framework 4.7.2中修复此问题.

  • 关于类固醇的DLL地狱. (10认同)
  • 只是另一个DLL地狱. (6认同)
  • 我的注意力集中在一个解决方法:http://blog.tdwright.co.uk/2017/11/21/update-getting-net-standard-apps-playing-nicely-on-nuget/ (2认同)
  • 是的,NuGet的get-nearest-framework逻辑在考虑其他版本之前会优先选择具有较低版本的目标框架(因此,“ net471”项目甚至会选择“ net35”而不是“ netstandard2.0”) (2认同)
  • 确实是 DLL 地狱。尝试转换一组中等大小的相互依赖的应用程序和库,即使只是添加新的 asp.net 核心应用程序(针对完整框架)引用旧共享库也绝对是系统库版本不匹配的噩梦,尤其是当 IoC 容器扫描程序集时对于类型。 (2认同)

Kev*_*oid 5

我也碰到了这个问题。您在评论中链接到Martin Ullrich的答案的博客文章使我找到了一个对我有用的解决方案:使用NuGet多目标。通过更改:

<TargetFramework>netstandard1.0</TargetFramework>
Run Code Online (Sandbox Code Playgroud)

<TargetFrameworks>netstandard1.0;netstandard2.0;net45</TargetFrameworks>
Run Code Online (Sandbox Code Playgroud)

在项目.csproj文件中。这将导致为每个目标框架分别构建项目,并且生成的NuGet包仅取决于NETStandard.Libraryfor netstandard1.0。由于NuGet选择net45任何完整的.NET Framework版本的二进制文件,因此可以避免安装软件包时不必要的依赖关系。

  • 谢谢@Kevinoid。那是我(OP)写的博客文章,总结了上面马丁的回答。很好,它来了整整一圈。 (2认同)