Skip to content
This repository has been archived by the owner on Sep 13, 2022. It is now read-only.

net462 referencing netstandard2.0 - can the large number of dlls be avoided? #545

Closed
ghelyar opened this issue Oct 22, 2017 · 14 comments
Closed
Milestone

Comments

@ghelyar
Copy link

ghelyar commented Oct 22, 2017

If I have an empty net standard 2.0 library and it's referenced by a net framework 4.6.2 "hello world" console application, building the net 462 application copies almost 100 dlls to the output directory, such as System.IO.dll, System.Console.dll, etc. It also copies netstandard.dll. From a netcoreapp2.0 console application, the only outputs are the 2 dlls for the projects.

If I copy just the console app .exe, the netstandard2.0 project's dll and netstandard.dll to their own directory, the exe seems to work (of course it's doing very little anyway, but System.Console.dll is not there, and I've also tried adding some simple System.IO calls, etc without any problems).

I had heard that all these System.* dlls were going to go away in netstandard 2.0 but that doesn't seem to be the case. Are all those other dlls necessary? If net framework 4.6.2 implements net standard 2.0, shouldn't having net462 be enough? Is there any way to prevent output of all of the individual System.* dlls if they aren't needed?

I have tried a .net 4.6.2 console application with the old csproj format and the old packages.config format, the old csproj format with the new PackageReference format, and creating a .net core console app to get the new "SDK" csproj format then changing its TargetFramework to "net462" with the same results in each case.

My reason for asking is that I have installers that need to be maintained, and at the moment this is causing me to both avoid pulling in nuget packages which target netstandard and avoid targeting netstandard in projects because of the maintenance burden of installing all of the dlls they output, but more and more nuget packages are just targeting netstandard in their latest versions now, which is preventing me from keeping them up to date.

@jnm2
Copy link

jnm2 commented Oct 22, 2017

I agree. I'm just not using NuGet packages on .NET Framework like System.Collections.Immutable simply because it's not worth adding 2 dozen assemblies when I could have a single exe.

The reason is that net471 is the first .NET Framework to actually contain netstandard20 APIs- the others use shims. I wish they were was just one net462–netstandard2.0 shim dll that ILMerged everything.

@Petermarcu
Copy link
Member

@terrajobst isn't there where we thought we could be smarter and only pull in the contract compat shims if needed?

@Petermarcu
Copy link
Member

@jnm2 , I believe the problem is the assembly identity of what the various libraries in the ecosystem reference. If they were IL Merged into a single assembly, they would lose their identity and the assembly wouldn't bind. I agree though, it sure would be nice to have less files :)

@terrajobst
Copy link
Member

terrajobst commented Oct 23, 2017

@Petermarcu

isn't there where we thought we could be smarter and only pull in the contract compat shims if needed?

We could, but it's debatable whether that's better or worse. Today, we're already having the problem that dynamic systems tend to have issues with missing binding redirects. I'm not sure automatic trimming would help our case as we're now adding one more option that could make the result fragile...

@ghelyar

I had heard that all these System.* dlls were going to go away in netstandard 2.0 but that doesn't seem to be the case

Yes and no. If you compile against .NET Standard 2.0, your code will only be compiled against netstandard.dll. However, for backwards compatibility with .NET Standard 1.x the other DLLs are still needed.

In general, .NET Standard dependencies were never meant to be deployed by the application. The idea is that they are built into the .NET implementation you're running on. Since we had a business goal to make .NET Framework 4.6.1 work with .NET Standard 2.0, we had to provide these additional files as part of the application. This will stop being the case starting with .NET Framework 4.7.1. In all other .NET implementations (.NET Core, Mono, Xamarin, UWP) they are already built-in.

@ghelyar
Copy link
Author

ghelyar commented Oct 23, 2017

It sounds like the long term fix is to target .net core 2.0 or .net framework 4.7.1 or higher, but I know that 4.7 had problems and 4.7.1 has only just been released.

for backwards compatibility with .NET Standard 1.x the other DLLs are still needed.

Does this mean that when targeting .net framework 4.6.2, if all dependencies are known to use netstandard2.0, the other dlls can be safely omitted?

@joperezr
Copy link
Member

It sounds like the long term fix is to target .net core 2.0 or .net framework 4.7.1 or higher, but I know that 4.7 had problems and 4.7.1 has only just been released.

Actually 4.7.1 will also need a few shims in order to be able to load .netstandard2.0 assemblies, but there are only 12 needed and with the tooling that we are about to release these are the only ones that will be copied to the bin folder. On 4.7.2, compatibility with netstandard will be inbox which means that if you retarget your app for 4.7.2 (once that is avaliable) the bin folder will only contain your dlls and pdbs.

Does this mean that when targeting .net framework 4.6.2, if all dependencies are known to use netstandard2.0, the other dlls can be safely omitted?

I don't think so. In 4.6.2 you still need the shims there because that is the way your netstandard library will be able to bind to the desktop runtime.

@jozefizso
Copy link

Because of these lots and lots of different System.*.dll files required by all the netstandard libraries we are forced to not updated our NuGet packages anymore.

It's not feasible to target .NET Framework 4.x with our app and then install 100 different .dll files with our app just because of this netstandard mess.

@jozefizso
Copy link

jozefizso commented Nov 30, 2017

In general, .NET Standard dependencies were never meant to be deployed by the application.

In reality .NET Standard completely messes up Visual Studio 2015 with latest update and we are forced to install all crazy System DLLs files with the app. (eg. https://github.com/dotnet/corefx/issues/25171)

@nzain
Copy link

nzain commented Mar 14, 2018

Me and my team were eager to transition to dotnet core 2.0 for our core libraries (some of those are used on embedded linux and on windows desktop apps, too).

I looked at
https://docs.microsoft.com/en-us/dotnet/standard/net-standard
which tells me that dotnet core 2.0 requires .net framework 4.6.1 (for Windows WPF desktop apps). I did not read the whole page, unfortunately. Above is stated that

the .NET Framework 4.6.1 implements .NET Standard 1.4

which is conterintuitive for me. It would have been nice to clarify that there is a discrepancy to be filled with extra-shipping of dlls.

Now we upgraded our whole ecosystem to .net Framework 4.6.2 (which is well available across target machines, but 4.7+ is not). Only today I realized that a small plugin made of three dlls now takes 116 dlls because it references our very dotnet core 2.0 library! Of course, every plugin is copied to its own directory within the application... that is a lot of overhead.

@jozefizso
Copy link

a small plugin made of three dlls now takes 116 dlls because it references our very dotnet core 2.0 library

That's really not feasible to deploy and support such large count of dependencies.

@jnm2
Copy link

jnm2 commented Mar 14, 2018

Oh hey, I forgot this issue existed!

I opened an issue at dotnet/sdk#1957 when I discovered (due to an in-house trimmer) that 72 of the 96 DLLs that you get when using a .NET Standard 2.0 library in a .NET Framework 4.6.2 project were not transitively referenced at all, and asked for a smarter SDK since those 72 extra shim assemblies would only be required if depending on a .NET Standard 1.* library. @ericstj said:

I agree that there would be an interest in reducing the set of files added so we can leave this issue open.

@nzain
Copy link

nzain commented Mar 15, 2018

Thanks @jnm2 for the hint. I can install the preview nuget package

<PackageReference Include="Microsoft.Packaging.Tools.Trimming">
  <Version>1.1.0-preview1-25818-01</Version>
</PackageReference>

and further add

<PropertyGroup>
  <TrimUnusedDependencies>true</TrimUnusedDependencies>
  <RootPackageReference>false</RootPackageReference>
</PropertyGroup>

to my net462 csproj (which references a netcore2.0 library). The RootPackageReference element is required to fix #667. This removes almost all extra dlls.

The alternative is to wait for .net framework 4.7.2 as Martin Ullrich explained in detail in his stackoverflow answer.

@StingyJack
Copy link

StingyJack commented Oct 17, 2018

In general, .NET Standard dependencies were never meant to be deployed by the application.

@terrajobst - That sounds great but in the meantime when I include System.Collections.Immutable in a 4.6.2 project, not only do I get an extra 90+ System.*.dll's, but i also get a big fat "Found conflicts... double click me" assembly binding warning.
image

We've been ignoring this (its happening for more than one project) for months now as the programs run just fine without adding those extra redirects, but it would be nice to be able to see any other warnings in the ErrorList and not have to deal with the repeating question of "should these be included in a hotfix/patch?".

Upgrading the individual projects to 4.7.2 does not seem like a solution for something that appears to be wrong with the Visual Studio IDE or build system. How else can we address all this extra noise?

EDIT: I read through an announcement post just now that offers package reference as a solution to this as it wont copy all the contents to the output folder. Using package reference means that we have to throw away a bunch of stuff, and it would create a small and constant mountain of extra work. Until package reference reaches feature parity with packages.config, we cant consider anything that requires it.

EDIT2: Reading that first EDIT back I'm not sure how package ref would make any difference for assemblies. They need to be copied to the output folder if the program is to run.

@terrajobst terrajobst added this to the .NET Standard 2.1 milestone Mar 13, 2019
@wtgodbe wtgodbe modified the milestones: .NET Standard 2.1, Future May 30, 2019
MetanoKid added a commit to MetanoKid/msbuild-flame-graph that referenced this issue Apr 1, 2020
Apparently (dotnet/standard#534), by using MSBuild via NuGet we're pulling System.Collections.Immutable with a version that references netstandard although it doesn't get pulled from NuGet.
Weirdly, the base dev environment works without this commit (VS2017 Community, .NET Desktop Development workload + .NET Framework 4.6.2 SDK and Targeting Pack).
Looks like our current target framework doesn't include all netstandard APIs (dotnet/standard#545) so this reference can be removed when we upgrade.
@terrajobst
Copy link
Member

We decided to close this as won't fix.

We learned that the code path that tries to be smart about not injecting the facades is very prone to errors. We don't believe this makes the servicing bar because it's likely to regress other scenarios.

@terrajobst terrajobst closed this as not planned Won't fix, can't repro, duplicate, stale Sep 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants