Standard: Creating .NET Standard 2.0 class library project will always have reference to Microsoft.NETCore.Platforms 1.1.0 by default

Created on 18 Sep 2017  路  34Comments  路  Source: dotnet/standard

Summary

Creating a .NET Standard 2.0 class library project should have correct reference to Microsoft.NETCore.Platform 2.0.0, but actual reference points to version 1.1.0 by default.

Detail description

Environments:

  • Windows 10 Anniversary Update
  • Visual Studio 2017 Enterprise with update: 15.3.3 and .NET Core workload installed (also tested with Visual Studio 2017 15.3.1 and using Community Edition)

Steps to reproduce:

  • Create a .NET Standard class library
  • expand the Dependency node on the Solution Explorer

This is the steps screenshot:
create_netstandard_library

By default, the creation of .NET Standard 2 class library should always point to v2.0.0 not the 1.1.0.

This is the close-up screenshot of the dependencies:

netstandard_dependencies

Expected result

The references should point to Microsoft.NETCore.Platforms _v2.0.0_ instead of older version, because this version is the version used by .NET Standard 2.0.

Is this a bug or by design?

cc @terrajobst and @weshaggard

Most helpful comment

@weshaggard
Just a humble suggestion, if this is by design, the display of Microsoft.NETCore.Platforms v1.1.0 will confuse most of us developers.
If .NET Standard only needs the metapackage of .NET Standard v2.0.0, then the Microsoft.NETCore.Platforms v1.1.0 should not be there at all. As far as I know, the Microsoft.NETCore.Platforms v1.1.0 package is for .NET Core, not for .NET Standard. CMIIW

All 34 comments

If this is by design, could we have an option to choose the versions of .NET Standard at the dropdown of .NET Framework version of the Create new project dialog?

Looks like this is by design currently. @ericstj do you think we need to update this version? Or perhaps even remove it as I'm not sure it is necessary in the NETStandard.Library package any longer.

@weshaggard
Just a humble suggestion, if this is by design, the display of Microsoft.NETCore.Platforms v1.1.0 will confuse most of us developers.
If .NET Standard only needs the metapackage of .NET Standard v2.0.0, then the Microsoft.NETCore.Platforms v1.1.0 should not be there at all. As far as I know, the Microsoft.NETCore.Platforms v1.1.0 package is for .NET Core, not for .NET Standard. CMIIW

The reason I had it there was because of back-compat with previous versions. Removing it can be potentially breaking if a package had RID-specific assets and didn't reference Platforms itself. Microsoft.NETCore.Platforms contains the definitions of RIDs and how they relate to each other.

Consider a simple package that does the following:
Dependencies: NETStandard.Library, 1.6.1
ref/netstandard1.0/foo.dll
runtimes/win/lib/netstandard1.0/foo.dll
runtimes/unix/lib/netstandard1.0/foo.dll

Install that package in a desktop app using RID win-x86, with no other dependencies. It will get the runtimes/win/lib/netstandard1.0/foo.dll implementation. Now, suppose the app updates to a NETStandard.Library package that doesn't reference the MS.NETCore.Platforms package. Restore will no longer have the RID graph and won't get any implementation from this hypothetical package.

@ericstj

Install that package in a desktop app using RID win-x86, with no other dependencies. It will get the runtimes/win/lib/netstandard1.0/foo.dll implementation. Now, suppose the app updates to a NETStandard.Library package that doesn't contain the MS.NETCore.Platforms package. Restore will no longer have the RID graph and won't get any implementation from this hypothetical package.

Then how do I target .NET Standard 2.0.0 by default? If I look at the project properties, the target is .NET Standard 2.0,0 but the Microsoft.NETCore.Platforms still points to v1.1.0.

I have also tried to create a .NET Core class library, now the version is correct: it shows version 2.0.0:

netcoreapp_vs2017_default_dependency_display

This .NET Core class library shows v2.0.0 by default.
Apologize for the debate may cause, but I'm still confused what the correct behavior should be.
My remaining confusion is: why the default template of .NET Standard will use Microsoft.NETCore.Platforms v1.1.0 while .NET Core app default template use Microsoft.NETCore.Platforms v2.0.0?

To me, IMHO it is still inconsistent and confusing. 馃槥

Since Microsoft.NETCore.Platforms brings in the runtime.json file, how does this come in for net* projects depending on netstandard2.0 libraries containing runtime assets? (e.g. RID-specific interop assets when running on mono and bundling it up into a netstandard package that PInvokes into a .dll, .dylib, .so file based on the RID restored for)

@ericstj

Any further info on this difference of default version in .NET Standard and .NET Core project template?
If the version of default Microsoft.NETCore.Platforms on .NET Standard needs to be updated to 2.0.0 as well, where could I submit PR to update the default project template?

Then how do I target .NET Standard 2.0.0 by default? If I look at the project properties, the target is .NET Standard 2.0,0 but the Microsoft.NETCore.Platforms still points to v1.1.0.

Don't assume that all the package versions must match the target framework version they have nothing to do with each other in general. We just try to line them up when we can. Sure, we can update NETStandard.Library to bring in new RIDs (and the new platforms package) but its not a requirement. Consider that moving forward the Platforms package will version at the same pace of the NETCoreApp (the primary cross-plat framework that makes use of RIDs) whereas NETStandard will version at a slower pace. So they happened to line up at this release but I expect they will not in the future.

I don't see a problem with updating NETStandard.Library to reference the latest Platforms package available (so long as we never make any breaking changes in the RID graph). Currently this is determined by baseline and stable versions here: https://github.com/dotnet/standard/blob/0642cc6f4f6b3e1a15704029dcfdfa431d662dd3/pkg/baseline/packageIndex.json#L98-L107, but we could just as well add the version metadata explicitly here (and all other instances): https://github.com/dotnet/standard/blob/9a35a69c32635144ea26f275e1fabf75b5000f08/netstandard/pkg/NETStandard.Library.dependencies.props#L136-L140

@dasMulli right now, those libraries would want to reference the platforms package specifically if they require the RID graph. My comment above was referring to existing packages which depended on it transitively via previous versions of NETStandard.Library. I gather you are suggesting that it would be nice if packages didn't have to do this. I tend to agree, though that would mean we'd need some sort of implicit PackageReference on all targeting-pack-based frameworks: desktop, xamarin.*, etc. /cc @dsplaisted @terrajobst

@ericstj

I don't see a problem with updating NETStandard.Library to reference the latest Platforms package available (so long as we never make any breaking changes in the RID graph).

Pardon, I mean not just updating references on the local .NET Standard project, but also update the version of the default template used in the .NET Standard class library project template. And as far as I know, there's no breaking change after having v2.0.0 set.

My last questions and proposal:

  • Could you elaborate what is RID graph?
  • Could I propose to update the version to 2.0.0? It it's accepted, where can I submit PR for this?

Thanks in advance!

To understand what a RID graph is you can see:
https://github.com/dotnet/corefx/blob/master/pkg/Microsoft.NETCore.Platforms/readme.md

See my above code pointers for where to change if you wish to update the dependency version. The PR can be submitted to this repo using one of the methods I mentioned. @weshaggard may have an opinion about which way he'd like to do it.

Thanks @ericstj !

To @weshaggard ,

may have an opinion about which way he'd like to do it.

Could you elaborate on which is the best way to do the update/modification? Thanks in advance 馃檪

Will memory and performance effect with and without .netstandard.dll in VS2015 Update 3?
@weshaggard @terrajobst

@ericstj

I tend to agree, though that would mean we'd need some sort of implicit PackageReference on all targeting-pack-based frameworks

I guess the only way with the least amount of headache would be for NuGet to add a mechanism for a default-RID graph that could be replaced by one pulled in via a package? That way each SDK (MSBuild / CLI) distribution (Or NuGet build) could contain a RID graph that could potentially be overwritten by the dependency graph. The danger of directly referencing Microsoft.NETCore.Platforms is getting into the package downgrade warning (=>error) danger zone. I guess that the targeting-pack based platforms would not need the latest and greatest RID graph anyway..

Can we select only required dll from .netstandard.dll list (out of 33000)? @terrajobst

Hmm, from the above discussion it seems .NET is still in versioning hell. If we add independent of .NET Core release versioning which follows scheme 1.0.0., 1.1.0, 2.0.0, 2.1.0 ... versioning of .NET Core assemblies which follows schemes of sort 4.0.0., 4.1.0 .... plus RID graphs we simply create combinatoric bomb.

Good luck to anyone trying to understand versioning, cross platform support and than derive an estimate of required framework/app footprint without resorting to automatic tools which when used in turn create confusion discussed here .... .

NET Standard was supposed to fix it but my impression is that currently it is still one additional factor in sufficiently complex version, platform and OS matrix which makes life .... hard. This opinion is based on recent experience with porting .NET Framework codebases of roughly 30 kloc each to .NET Standard 2.0.

See my above code pointers for where to change if you wish to update the dependency version. The PR can be submitted to this repo using one of the methods I mentioned. @weshaggard may have an opinion about which way he'd like to do it.

For better or worse we will likely never be able to fully align the versions between the NETStandard.Library package and the Microsoft.NETCore.Platforms package because it will cause a cycle in the dependencies between the standard and corefx repos. We would always have to be a release behind. My opinion would be to remove it from NETStandard.Library package completely if we can convince ourselves that it won't be a breaking change.

My opinion would be to remove it from NETStandard.Library package completely if we can convince ourselves that it won't be a breaking change.

@weshaggard It looks like the best option which would firstly remove confusion and secondly expose the true role of .NET Standard assemblies - they are just ref facades to APIs implemented somewhere else. This would make more than clear that one cannot run an application on ... .NET Standard 馃槃

@weshaggard

My opinion would be to remove it from NETStandard.Library package completely if we can convince ourselves that it won't be a breaking change.

Thanks! So what would be the best way to achieve this? And how to test for breaking compatibility? Please elaborate.

@weshaggard and @ericstj

Apologize if I might troll you guys, but could you confirm which way is the best way to remove or to fix this confusion? Because it's been more than 8 days since your last reply by @weshaggard.

My opinion would be to remove it from NETStandard.Library package completely if we can convince ourselves that it won't be a breaking change.

Or could I submit a PR to dotnet/standard/tree/master/pkg/baseline/packageIndex.json#L98-L107 to point to version 2.0.0?
Or has this issue reached any decision?

I think I've already mentioned that it would be a breaking change.
https://github.com/dotnet/standard/issues/497#issuecomment-330309192

All you need is a package to use RID-specific assets, only reference NETStandard.Library, then install on a framework like desktop that doesn't provide its own reference to the RID graph. If you removed the reference to Microsoft.NETCore.Platforms from the latest NETStandard.Library and installed that in the same project the hypothetical package above would not resolve any assets.

Perhaps @weshaggard is implying that we could scour nuget to determine if such a package exists? I'm not sure. I can construct it fairly easily to demonstrate the problem.

/cc @eerhardt

Actually, Microsoft.NETCore.Platforms is technically only needed for the concrete (non-NETStandard) frameworks, since those are the only ones that can actually restore with a RID.

We could remove it from only the NETStandard2.0 dependency group and that'd solve the visual problem you pointed out. We already declare specific dependencies for all the concrete frameworks that implement NETStandard2.0, and those will need to keep the reference for compatibility reasons we've already discussed.

So the fix would be to modify this:
https://github.com/dotnet/standard/blob/d03f5dba6aa1195ece4028de8170d95359d945ff/netstandard/pkg/NETStandard.Library.dependencies.props#L136-L140

To instead be:

    <!-- we need an empty dependency group to prevent netstandard1.x references from applying to 2.0 -->
    <_dependency Include="_._">
      <TargetFramework>netstandard2.0</TargetFramework>
    </_dependency>

We could remove it from only the NETStandard2.0 dependency group and that'd solve the visual problem you pointed out. We already declare specific dependencies for all the concrete frameworks that implement NETStandard2.0, and those will need to keep the reference for compatibility reasons we've already discussed.

@ericstj thanks! Now I fully understand some of the compatibility reasons.

Now that you have pointed generous hints to fix this, I'm preparing a PR for this.
Could you tell me or elaborate how to test this fix on my machine? Or do I have to submit the nuget package to other nuget server such as MyGet and test it from there?

A good thing to do when changing a package is to do a clean build before making your change, then rename the bin\packages\debug\specs folder (to specs.old, for example). Make your change and build the pkgproj again. Examine the diff between the old specs folder and the new one.

You will now have a new package in the \bin\packages\Debug folder.

You can add this folder as a nuget source on your machine, either through package manager settings in visual studio or through a nuget.config file.

Once you've done this, you can test using your new package in different project types. I'd consider the following:

  1. NETStandard library project targeting 1.x and one targeting 2.0. Here set the version to match the one you built using
<NETStandardImplicitPackageVersion>2.1.0-previewXXXXXXX</NETStandardImplicitPackageVersion>

This is needed because NuGet will prevent you from installing the package because it is referenced by the SDK. The SDK provides its own mechanism for specifying the version referenced. Once you have done this, ensure that MS.NETCore.Platforms is no longer referenced.

  1. A net461 project. Install the package and ensure that MS.NETCore.Platforms is still referenced.
  2. A netcoreapp2.0 project. Install the package and ensure that MS.NETCore.Platforms is still referenced.

Anything else you'd like to try out :)

Guys looks like this is the same issue i raised in core team so what is final decision on this? is it bug in default template or is this correct behavior?

@rdzidziguri
It is not a bug nor an issue. Please follow up the discussion above, especially explanation of @ericstj and @weshaggard .

@eriawan were you going to make a PR for this?

@Petermarcu yes, I'm in the middle of working on it.

Apologize, I'm still struggling to update the standard/netstandard/pkg/NETStandard.Library.dependencies.props
and test the resulting .NET Standard metapackage, sometimes it works, sometimes it doesn't.

I'll update you next week or sooner if I can repro my problems. Or have you already worked on this?

Sounds good. No, I'm not working on it. Was just wondering what the next steps on this issue were as I'd like to see what it will take to get it addressed. Thanks for helping out!

Any update on this guys? how soon we are going to see that PR?

@rdzidziguri
Please be patient, I'm still testing it.

I face the same issue today.
Environments:
Windows 10 Professional 1703 15063.786
Visual Studio 2017 Enterprise with update: 15.5.2 and .NET Core workload installed, Framework 4.7.1

But something magic happened next:
I referenced a wcf service using the wcf service tool, after what, the target .NetCore.Platforms changed to 2.0 !
Do someone can explain this ?

Update :
When I tried to remove System.ServiceModel.Security (added by the wcf service tool), Visual Studio informed me that it's going to change the target NETCore.Platforms to 1.1.

It would seem that if your .net standard project references a .net core package then Microsoft.NetCore.Platforms changes to 2.0.0 as a way of resolving that dependency without using two versions of the same library. This seems to be a safe change when it happens by accident, so I am curious why this is still the default almost a year later.

I'm closing this now. To me, it's seems it's just an oddity in the UI. As we said, we'll never be able to keep all package version in sync with the TFM -- in the end, being packages means they can ship independently and thus also have to version independently.

Was this page helpful?
0 / 5 - 0 ratings