Why is my standard NuGet.NET package running so many dependencies?

I dumped the .NET Standard and NuGet projects with. I have a working draft and uploaded it to NuGet.org . My project is targeting .NET Standard 1.3, which should support the .NET Framework 4.6 and .NET Core 1.0.

But when I tried to add my project (via NuGet) to a new .NET Framework 4.6 project, dependencies were allowed for 47 packages! All of them are system libraries and are dependent on Microsoft.NETCore.Platforms or NETStandard.Library 1.6.1. ( Gist full PM output. )

My project imports ( using ) several libraries, none of which I added manually; that is, all libraries that come with the .NET standard. These libraries:

  • System
  • System.Text
  • System.reflection
  • System.linq
  • System.Collections.Generic;

The fact is that I decided to make my project target .NET Standard, because I wanted it to work without problems in the .NET Framework and .NET Core applications. I thought that all the Standard needed was to set a minimum level of compatibility. Apparently, I assumed (possibly erroneously) that libraries such as System.Console would be automatically available in either Core or Framework.

I did not notice anything like this when I tested my standard project as a dependency in a Framework and Core project within the same solution, so I suspect it might be NuGet.

What's going on here? And how can I make my .NET Standard library available on NuGet without a huge list of dependencies?

Is this a problem with how I defined my NuGet package? Or am I fundamentally misunderstood something?

+42
nuget .net-standard
source share
3 answers

You haven’t done anything wrong, this is about to happen. If you want your new DLL to be added to a new .NET Framework project, you need to target the .NET Standard 2.0 for your library, expecting a version of the .NET Framework that natively supports both the API and the build version. for 4.7.2 (while the .NET Framework 4.7.1 supports all APIs, there were errors in how some assemblies were versions, and therefore the toolkit (VS 2017 15.5+) will add additional assemblies to fix this).

What you see is a side effect of creating the .NET standard and supporting supported frameworks. It also depends on the standard version of .NET you choose and the tools used to reference the library package.

In .NET Standard <2.0, you refer to the NETStandard.Library meta-package, which, in turn, refers to additional packages ( System.* ). These packages contain reference assemblies that make up the "Standard .NET Standard Contract" - a set of APIs and assembly names + versions.

When the NuGet package that you create for .NET Standard 1.0-1.6 then references the application, these individual packages do not result in link assemblies, but rather an implementation assembly for the framework that the application is aimed at.

For .NET Core, they correspond to assemblies that are already part of the runtime, so DLL files will not be located next to the embedded application. However, this changed when the new package package for .NET Core 1.1 ( NETStandard.Library version 1.6.1) was released. This led to the creation of applications built for .NET Core 1.0, which resulted in new builds for implementation that were to be included in .NET Core 1.1 (fortunately, version 1.1 used "long-term support" because it caused discussion about which builds are part of the LTS promise).

In the .NET Framework, these libraries (with a few exceptions, such as System.Net.Http ) do little - they simply forward system assemblies. So, for example, a “contract” defines that System.Object is defined in the System.Runtime.dll assembly. Thus, the System.Runtime.dll file that you get into the .NET Framework application contains System.Runtime.dll , which contains the type forward to.NET Framework mscorlib.dll .. Core Core already contains another System.Runtime.dll that does something different for this platform. This mechanism allows one DLL file to work on both platforms, because these types of forward and additional implementations provide the same "contract" (types + assemblies or assemblies) that work on both implementations.

.NET Standard 2.0 aims to reduce the number of packages and DLLs required, as well as to remove the required updates to NETStandard.Library when releasing a new version of .NET Core.

So, for .NET Standard 2.0 and .NET Core 2.0, the NETStandard.Library package contains only link assemblies for compiling the code for the project, but the resulting NuGet package no longer depends on this package. Therefore, when you create a library targeting .NET Standard 2.0 and publish it, it will not have NuGet dependencies (unless you add additional ones).

The logic of what “support libraries” to enter when using the .NET Standard library has been transferred to the snap-in that is used during assembly. Therefore, when the library containing the link to netstandard.dll is added to the .NET Framework project, the toolkit then adds the necessary support DLLs based on the version of the .NET Framework used. This was done for .NET Standard 2.0, as well as for .NET Standard 1.5+, because the .NET Framework 4.6.1 was retroactively compatible with .NET Standard 2.0 (previously 1.4) using these DLL files. The same tool also ensures that even if NuGet packages are somehow included in such an application project, any .NET Standard implementation libraries created through NuGet are removed from the assembly. Therefore, if you reference the .NET Standard 1.0 NuGet package that was created when .NET Core 1.0 was released, all of its NuGet dependencies are truncated, and instead you get the support libraries that come with the build tools.

The idea was that the .NET Framework 4.7.1 would contain all the necessary "inbox" assemblies, so netstandard.dll , System.Runtime.dll , etc. are part of the .NET Framework and any .NET Standard 1.0-2.0 DLL file will just work, the problem is that these inbox DLLs had a too low version number for some assemblies, so the libraries could not load - this was fixed by changing the toolkit again to include DLL files with higher version numbers as library support, which in turn go to the .NET Framework inbound assemblies. This is planned to be installed in the .NET Framework 4.7.2.

+48
source share

I also ran into this problem. The blog post that you linked in the commentary on Martin Ullrich’s answer led me to a solution that worked for me: using NuGet multi-purpose targeting . By changing:

 <TargetFramework>netstandard1.0</TargetFramework> 

in

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

in the project file .csproj . This leads to the fact that the NETStandard.Library project NETStandard.Library separate for each target infrastructure, and the resulting NuGet package depends only on NETStandard.Library for netstandard1.0 . Since NuGet selects net45 for any full version of the .NET Framework , this avoids unnecessary dependencies when installing the package.

+3
source share

If you are running .NET 4.6 and trying to figure out which ones you need to deploy, look for CSPROJ \System. in your file \System. (not a regular expression) - these are the packages in the packages that should be copied with your application, the rest should be framework DLLs.

To test this theory, get rid of them in your local assembly and run it to make sure that the deployed version does not break ...

  • In the bin folder, run the command dir/b System*.dll > textfile.txt to get a list of DLLs.
  • inserted "DEL" in front of all names,
  • I also found Microsoft.Win32.Primitives.dll and netstandard.dll which were not needed in 4.6 as well.
  • and save it as a .CMD file - well, not in the bin folder, okay?
  • add it as a post build process. $(ProjectDir)DeleteSuperfluousSystemDlls.cmd

I would like to exit .NET 4.6, but AutoCAD does not work well when the environment is too modern for this.

edit...

Here is some copy paste ...

Step 1 - in your CSPROJ file ...

 <!--https://stackoverflow.com/questions/2387456/msbuild-exec-task-without-blocking/21181071#21181071--> <!--Launch a Process in Parallel--> <UsingTask TaskName="ExecAsync" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> <ParameterGroup> <!--The file path is the full path to the executable file to run--> <FilePath ParameterType="System.String" Required="true" /> <!--The arguments should contain all the command line arguments that need to be sent to the application--> <Arguments ParameterType="System.String" Required="true" /> </ParameterGroup> <Task> <Code Type="Fragment" Language="cs"><![CDATA[ System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo(FilePath, Arguments); processStartInfo.UseShellExecute = true; System.Diagnostics.Process.Start(processStartInfo); ]]></Code> </Task> </UsingTask> <Target Name="AfterBuild"> <ExecAsync FilePath="$(ProjectDir)\Deployment\DeleteSuperfluousSystemDlls.cmd" Arguments="$(TargetDir)" /> </Target> 

Step 2. Batch file ...

Edit the list created by dir/b System*.dll > textfile.txt so that it looks something like this

 del %1Microsoft.Win32.Primitives.dll del %1netstandard.dll del %1System.AppContext.dll del %1System.Collections.Concurrent.dll del %1System.Collections.dll del %1System.Collections.NonGeneric.dll del %1System.Collections.Specialized.dll del %1System.ComponentModel.dll 

but do not forget to delete those that are really needed so that they are not deleted.

0
source share

All Articles