dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.73k stars 1.07k forks source link

Unable to upgrade a package from netcoreapp to netstandard as netstandard adds APIs. #3784

Open jhudsoncedaron opened 5 years ago

jhudsoncedaron commented 5 years ago

When trying to make a multi-library targeting both netcoreapp and netstandard, the dotnet dependency resolver does something surprising. It prefers any arbitrary old version of netcoreapp over a very new version of netstandard.

So when netstandard adds enough apis that we can switch from netcoreapp to netstandard, it doesn't work. It actually prefers the really old netcore version over the netstandard version.

I went back and tried it on the 2.1 tooling and it's been doing it for awhile.

Demonstration:

netcoreresolve.zip

Expected output: "Moniker: netstandard2.0" Actual output: "Moniker: netcoreapp1.0"

I have some long-running multi-target libraries where I actually have to knock out features at build time when targeting old platforms, so this behavior is obnoxious.

0xd4d commented 5 years ago

This is expected and I'm sure it's documented somewhere. If you add netstandard2.0 support to a library and it already targets netcoreapp1.x, you should also add a netcoreapp2.0 tfm.

   <PropertyGroup>
-    <TargetFrameworks>netcoreapp1.0;netstandard2.0</TargetFrameworks>
+    <TargetFrameworks>netcoreapp1.0;netcoreapp2.0;netstandard2.0</TargetFrameworks>
   </PropertyGroup>

Or just drop all netcoreappx.x tfms and just use netstandard2.0

jhudsoncedaron commented 5 years ago

@0xd4d : You do realize this means in the end shipping a bunch of useless binaries in the nuget package right?

0xd4d commented 5 years ago

The netcoreapp1.0 binary is needed if someone targets netcoreapp1.0 - 1.1.

The netcoreapp2.0 binary is needed if someone targets netcoreapp2.0 - 3.1.

The netstandard2.0 binary is needed if someone targets a netstandard2.0 compatible tfm, not including any of above netcoreapp tfms.

So they're all needed.

If you care about nuget size, you can choose to only target netstandard2.0.

FYI, netcoreapp1.0-1.1 is not supported by MS anymore so that tfm can be removed leaving you with only having to use netstandard2.0..

https://dotnet.microsoft.com/platform/support/policy/dotnet-core

   <PropertyGroup>
-    <TargetFrameworks>netcoreapp1.0;netstandard2.0</TargetFrameworks>
+    <TargetFrameworks>netstandard2.0</TargetFrameworks>
   </PropertyGroup>
dasMulli commented 5 years ago

NuGet will match the slice of the package it considers the "nearest" TFM to the TFM you are referencing from.

The nearest-TFM resolution will consider any slices that are the same target framework - any version - first before considering falling back to "compatible" target frameworks like .NET Standard or PCLs.

This has been bothering a few authors as well, esp when they have old net35 or net45 slices that they maintain and thus need to add newer TFMs like net472 as well because .NET Framework projects will never use netstandard2.0 if any net* slice is provided. But this makes the resolution very reliable knowing that if you have a version specific to .NET Framework or .NET Core, then an update won't suddenly change something different and possibly break the application.

jhudsoncedaron commented 5 years ago

Long time before I can drop .NET Core 1.0 because it's being used in the secure key signing environment with no access to the internet.