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

Visual Studio uses netstandard1.3 instead of net452 when consumed by a net461 project #580

Closed
JanEggers opened this issue Nov 11, 2017 · 13 comments

Comments

@JanEggers
Copy link

JanEggers commented Nov 11, 2017

i am contributing to a library https://github.com/chkr1011/MQTTnet this library targets netstandard1.3 and net452.

recently we get complaints by consumers of the library that we have added so many dependencies.

if a project targeting net461 all dependencies that are required for netstandard 1.3 are forced on that project.

why is that the case?

My understanding is that visual studio should use net452 dlls when targeting net462 not netstandard1.3 + added polyfill dependencies

if this issue is in the wrong place feel free to move it where it belongs i didnt know a better place to start with.

@Petermarcu
Copy link
Member

@joperezr
Copy link
Member

I just tried this locally with a package that has two dlls, one in lib/netstandard1.3/myLib.dll and one at lib/net452/myLib.dll. Then I created a Console app that targets .NET Framework 461 and I correctly got the asset from lib/net452/ as expected. I am using the latest released VS, 15.4. Can you share the name of the package so that I can take a peek at that case in particular and see what is going on? Also, can we get more info on which VS version are you using to restore?

@JanEggers
Copy link
Author

the package is https://www.nuget.org/packages/MQTTnet/2.5.1

the repository with the source is already mentioned above.

if i add net461 targetframework to

MQTTnet/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj

my output is the following:

net452 is ok:

image

net461 contains system.security dlls that are only included for netstandard

image

https://github.com/chkr1011/MQTTnet/blob/0844abd7e568fd38ffa5464d964b5e089b53abe2/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj#L51-L69

https://github.com/chkr1011/MQTTnet/blob/develop/Build/MQTTnet.nuspec

so i actually dont know how to verify what dll is chosen as they all have the same name. but it seems all dependencies in the group netstandard 1.3 are included.

@JanEggers
Copy link
Author

i just verified it, the dll itself is chosen correctly

i added the following code to the package:

public static class TargetFraameworkProvider
    {
        public static string TargetFramework
        {
            get
            {
#if NET452
                return "net452";
#elif NET461
                return "net461";
#elif NETSTANDARD1_3
                return "netstandard1.3";
#elif NETSTANDARD2_0
                return "netstandard2.0";
#elif WINDOWS_UWP
                return "uap10.0";
#endif
            }
        }
    }

that prints 452 when included from 461 but the system security dlls are still copied to the ouput folder although they should not be included.

@JanEggers
Copy link
Author

also if i add net461 to that project (so there is an exact match later on) its bin folder already contains the dlls that are not present in net452 bin folder

@dasMulli
Copy link

Those are likely the netstandard 2.0 shims for net461+ that are copied from C:\Program Files\dotnet\sdk\2.0.2\Microsoft\Microsoft.NET.Build.Extensions\net461\lib during the build that allow .net standard 1.5+ dlls to run on net461 since your dependency closure includes dlls built for .net standard (the Microsoft.Extensions… packages you reference)

@JanEggers
Copy link
Author

JanEggers commented Nov 12, 2017

that allow .net standard 1.5+ dlls to run on net461

but why are these shims not required for net452?

also when i downgrade the extension packages to 1.0.2 which depends on netstandard 1.1 i still see the same behavior for net461.

and why arent these shims visualized in the dependency tree of the included nugets?

@dasMulli
Copy link

because the logic only kicks in for net461+ https://github.com/dotnet/sdk/blob/aeb50655bbf9ee652c21b1f1375c6107fe1f0790/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/msbuildExtensions/Microsoft/Microsoft.NET.Build.Extensions/Microsoft.NET.Build.Extensions.NETFramework.targets#L17-L18

If you retarget to 4.7.1, you shouldn't get additional assemblies - using 2.0.2 / VS 15.4.* (15.5 should add back a few again since there are bugs because of how the assemblies in 4.7.1 are versioned)

@dasMulli
Copy link

okay that wasn't a good explanation 😅 @joperezr can probably give a good.
From my understanding, the logic in NETStandard.Library is sufficient for older netstandard and .net framework versions but in order to get 1.5+ working on net461+ the extension logic needs to add additional assemblies and trim out conflicting assemblies coming from NuGet packages.

@JanEggers
Copy link
Author

JanEggers commented Nov 12, 2017

hmm sry I just dont understand why that is brought in with a targets file. For me this is some kind of black magic. Why doesnt the nuget i reference include everything it needs for the target platform i specify. so i can clearly see what i depend on?

i created a nuget with the downgraded packages. and if i now use that nuget none of that additional dlls are copied to the consuming package, when adding a project reference they are copied. that is confusing me even more.

@joperezr
Copy link
Member

@dasMulli is right, those libraries you are seeing are just the shims that will enable running netstandard based dlls on desktop. I agree that is not great that all of these files are being brought in by a targets file, but here is the reasoning behind it. We started having a lot of users that wanted to consume .NET Standard components on desktop, and they were all failing when trying to run because they were missing these shims. Originally, we decided that the proposed solution was that if you wanted to do this, you had to add a reference to the package NETStandard.Library.NETFramework which would pull in the shims for you. The problem was that there were A LOT of people hitting this, and it wasn't obvious that the workaround was adding the reference to this package. That is why we opted to have the fix in the tooling instead, so now, if you are targeting desktop, we do some logic (in that targets file) to try to find out whether or not you will need the shims, and if we think you will, then we copy them out to the bin folder, that way, consuming .NET Standard components from desktop just works out of the box. That said, our logic in that targets files has some bugs that we are currently addressing since it doesn't inject the shims all of the times when they are needed, but we believe our next release should cover much more scenarios. As I said, I agree with you that just injecting these dependencies by magic is not ideal, but we thought at the time that it would be the best solution for most users that just want to use their components against different runtimes.

@JanEggers
Copy link
Author

thx for clarifying.

@dasMulli
Copy link

From my opinionated end-user perspective I actually prefer this to be done by the tooling. It would be hard to track which projects would need updates to a NETStandard.Library.NETFramework package for particular .net framework versions and if bugs are discovered (as with net471 recently), I can simply update the tooling and not go through some form of migration for every project (even if it is just updating packages).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants