I'm writing a C# library targeting .NET Standard 2.0 and .NET Framework 4.6
In other projects (targeting .NET Framework 4.6.1):
When I directly references my library project, the number of produced DLLs are reasonable.
However, when I publish the library to Nuget and install it in other projects, I get an additional 100+ files, and almost all of them are System.*
I wonder if this is due to me misconfigure something when publishing the library to NUGET, or because of something else?
This is expected. Those additional files are required at runtime to make sure your .NET Standard 1.* libraries run on .NET Framework 4.6 and higher.
You can read more about this here.
Related
Setup
Say I have a .Net Standard 2.0 class library project and I add a Nu NuGet package that is compatible with .Net Standard 2.0 to it.
I then reference that class library project from both a .Net Framework console project and a .Net Core console project.
To restate with a picture:
Question
How does each of the console applications deal with getting the right NuGet code for their type of application?
Notes
Note: I tried this using Microsoft.Extensions.DependencyInjection, and it works fine in the .Net Core 3.1 console app, but throws a "File Not Found" exception in the .Net Framework 4.7.2 console app (looking for the Dependency Injection DLL). This leads me to believe that .Net Standard 2.0 NuGets are really .Net Core NuGets...
Note to the Note: I am trying to understand what happens here, not fix the "File Not Found" issue. (That is easily fixable by referencing the Microsoft.Extensions.DependencyInjection NuGet in the .Net Framework 4.7.2 console app).
In your scenario two different package resolution startegies are used. There is the old way of managing packages with packages.config and the new way with PackageReferences. There is also the old project format of .NET Framework projects and the new SDK-style format that was introduced for .NET Core, but is also usable in .NET Framework applications.
With the old project format that is still used by most existing .NET Framework applications regardless of packages.config or PackageReference, the .NET Framework Console application is only able to access the class library, but not the assemblies of its referenced NuGet package, because it is not a direct reference but via your library, hence indirect. This is als called a transitive dependency.
In the new SDK-style project format with PackageReference, this is fundamentally different. There, transitive dependencies are possible. This means, that your .NET Framework console application can access the class library project, as well as its referenced assemblies via the NuGet package.
The SDK-style format with PackageReference is the default for .NET Core projects, so they support transitive dependencies out of the box. Only with the old project format you have to add NuGet packages manually, because it cannot access the transitive dependency through the class library. You can migrate existing .NET Framework projects to the new SDK-style format, to enable the same behavior as in .NET Core.
I'm certain there's probably a bunch of things going on here that I don't understand well enough, so forgive me if this is a stupid question or if there's obvious details missing.
I have a Visual Studio 2015 solution that I've upgraded from .NET 4.5.1 to .NET 4.7.1. The solution consists of a website (not web app) project, and several libraries. The libraries don't really have any dependencies (except eachother) and while they are targeting .NET 4.7.1, they don't use, need, or reference .NETStandard.Library.
When I compile one of the libraries in particular, it keeps copying a bunch of .NET 4.7.1 facade dlls into the website bin folder. Unfortunately, the website is a Kentico 11 application, and it keeps trying to load the System.IO.Compression.ZipFile facade, and chokes on it because it's a reference assembly, not a real assembly.
If I delete the .dll, everything runs fine... but I don't want to delete it every time or add a post-build event to delete it. That's just silly.
Can anyone help me understand what's going on here, and how to clean it up?
Kentico 11 can only target up to .NET 4.7 so in an attempt to fully support your .NET 4.7.1 libraries I believe it is copying in those additional facade DLLs. This is based on the .NET 4.7.1 release announcement, specifically this section:
BCL – .NET Standard 2.0 Support
.NET Framework 4.7.1 has built-in support for .NET Standard 2.0. .NET Framework 4.7.1 adds about 200 missing APIs that were part of .NET Standard 2.0 but not actually implemented by .NET Framework 4.6.1, 4.6.2 or 4.7. You can refer to details on .NET Standard on .NET Standard Microsoft docs.
Applications that target .NET Framework 4.6.1 through 4.7 must deploy additional .NET Standard 2.0 support files in order to consume .NET Standard 2.0 libraries. This situation occurred because the .NET Standard 2.0 spec was finalized after .NET Framework 4.6.1 was released. .NET Framework 4.7.1 is the first .NET Framework release after .NET Standard 2.0, enabling us to provide comprehensive .NET Standard 2.0 support.
https://blogs.msdn.microsoft.com/dotnet/2017/10/17/announcing-the-net-framework-4-7-1/
Reference that led me to this conclusion:
https://github.com/Particular/NServiceBus/issues/5047#issuecomment-339096350
Update:
I was unable to reproduce your issue in Visual Studio 2017 Version 15.6.2.
I installed a Kentico 11 website project targeting .NET 4.7. I then created a library project that targeted .NET 4.7.1. I added some dummy code to the project to make use of Sysetem.IO.Compression and System.Net.Http namespaces. I added a reference to the project from Kentico and ran a build. No facade DLLs where copied to the bin folder.
This post indicates the issue was fixed in Visual Studio version 15.6 https://github.com/dotnet/sdk/issues/1647#issuecomment-364999962
The additional files that get deployed to your bin folder are needed to support referencing and running .NET Standard 1.x and .NET Standard 2.0 libraries in your .NET Framework application.
We have documented this as a known issues with .NET Framework 4.7.1.
The presence of those additional files is not sufficient however. You also need to have binding redirects generated in order to ensure types correctly unify across libraries.
Visual Studio 15.6.3 (and later) have a change that will automatically generate those binding redirects for your application.
.NET Framework 4.7.2 addresses the issues that require those additional files to be deployed with your application. When targeting or running on .NET Framework 4.7.2 you won't have any additional files copied to your bin folder and no binding redirects will be automatically generated.
You can try .NET Framework 4.7.2 and see what's new by following the instructions here.
References to assemblies have their own properties. You can specify there if you want to copy the assembly to the build output directory. Maybe somewhere it is set to true. To check that go to Solution Explorer in Visual Studio and right click on the referenced assembly. Then click Properties and look for property named "Copy Local".
I'm working on migrating a large code base of libraries in a direction to eventually support .NET Core. Currently, everything is based on .NET Framework. I have a set of library projects which are consumed by several web applications.
The plan is to convert the library projects over to .NET Standard 2.0 so that they can be consumed by both .NET Framework (version 4.7.1) based websites and by new .NET Core (version 2.0) websites. I've done some test solutions which proved that this can be done.
To convert the first library over to .NET Standard I had to leverage the Windows Compatibility Pack for some of the features that are not part of .NET Standard. Some features such as SqlClient and some System.Drawing tools had to be imported into the library. All of this worked but an issue turned up when trying to bring my library into code which was still targeting .NET Framework.
Even though the namespaces were the same, the consuming code could not see the objects (such as Image or SqlConnection) unless I added the same Windows Compatibility Pack libraries into the consuming project. If anything, I would have expected this to cause issues as I now have two identical classes (same namespace and object name) in different assemblies. Fortunately, it is working. At least the unit tests are still passing.
Is this the way the Windows Compatibility Pack libraries are supposed to work? I had hoped that they would provide the functionality in the .NET Standard or .NET Core code but allow the .NET Framework to still use its own implementation.
The compatibility package references a few of the assemblies that were brought back to increase the compatibility of .NET Core with .NET Framework.
The way the package works is that there is a meta-package (the one that you reference) and it has references to individual packages that actually contain the implementation. Those individual packages have different assets depending on the target framework.
Take for example System.IO.Ports. That package contains the following assets (and a few more things that are not directly relevant to this):
net461
netstandard2.0
The netstandard2.0 asset contains the code that implements the System.IO.Ports functionality. You will use this if you are building a .NET Core application.
The net461 asset type-forwards the types exposed by the System.IO.Ports namespace to the assemblies you will find in the .NET Framework installation. You will use these if you are building a .NET Framework application (like a console application of web site).
This means that when you are consuming your library on .NET Core, you are using the implementation that was ported and made to work on .NET Core.
When you are using your library on .NET Framework you will use the implementation that is part of .NET Framework.
I'm trying to wrap my head around the NuGet package system. Recently I released a class library for NuGet, targeting only .NET Framework 4.5.2, but as of demand, I decided to create a new class library targeting .NETStandard 1.4.
Here's where I get lost. Is is possible for me to target multiple frameworks in a single NuGet package, taking this scenario of having two different projects?
Would it make sense for me to remove the .NET Framework 4.5.2 project, and replace it with my .NETStandard 1.4 project? The code is 100% the same.
Any suggestions or best practices to navigate through such a scenario?
If you need to support .NET Framework 4.5.2, you'd need to lower the version of .NET Standard to 1.2 as per compatibility matrix since .NET Standard 1.4 packages can only be used on .NET Framework 4.6.1+.
If this is not possible for you, you can multi-target your project so that the same project is built for a version of .NET Standard and .NET Framework and packages into the same NuGet package. .NET Framework projects referencing that package will prefer the .NET Framework dll over the .NET Standard dll in the same package.
You can do this by changing the .NET Standard project from
<TargetFramework>netstandard1.4</TargetFramework>
to
<TargetFrameworks>net452;netstandard1.4</TargetFrameworks>
By changing the property to TargetFrameworks (plural), the project will now be built twice - once per specified framework.
I really wanted to be a good citizen... copied all my classes to .net standard 1.6 libraries. Just to find out that my test DLL can't use it. I get the following error
Project X targets '.NETStandard,Version=v1.6'. It cannot be referenced by a project that targets '.NETFramework,Version=v4.6.1'.
Of course, when I check .Net Standard (https://learn.microsoft.com/en-us/dotnet/articles/standard/library) it says that with 1.6 it can target 4.6.1.
I tried 4.6.2 without better luck. I installed the .net standard 1.6.1 NuGet package. Anyway, you guys are awesome, I'm sure you'll tell me which stupid mistake I'm making that is preventing me from doing something as basic as running unit tests with a .net standard library.
Thanks
P.S. I did find a work around (kind of) by using a .net core unit test project instead of a .net framework one. It doesn't solve my problem, so I can't mark that as an answer, but at least I can go back to coding...
You need to upgrade to .Net Core SDK 2.x+
Once that is installed restart your machine and you should be able to reference NetStandard 1.6 in .Net Framework 4.6.1+
With .Net Core SDK 1.x you can only reference Net Standard 1.5 in .Net Framework 4.6.2
Best would be to upgrade your Net Standard project to version 2.0 if you can.
In case of errors with similar titles that are targeting different versions of .net framework, this usually means that you need to (install if already not and) change the target of your project to newer/newest version of .net framework to comply with the project that targets newer .net standard.