NuGet / Home

Repo for NuGet Client issues
Other
1.5k stars 252 forks source link

Unnecessary NU1202. PackageReference versus Reference #8644

Closed 3F closed 5 years ago

3F commented 5 years ago

Hi,

Can someone clarify NU1202 restriction? I still don't understand, Why this https://github.com/dotnet/standard/blob/master/docs/versions.md#net-standard-versions is not possible for nuget project?

Just for the cases like this https://github.com/3F/MvsSln/pull/21 and other?

Why/ if I can like this:

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
  <Reference Include="Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <HintPath>..\packages\microsoft.build.15.9.20\lib\net46\Microsoft.Build.dll</HintPath>
    <Private>True</Private>
  </Reference>
</ItemGroup>

But not like this:

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
  <PackageReference Include="Microsoft.Build" Version="15.9.20" />
</ItemGroup>

this:

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
  <Reference Include="Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <HintPath>..\packages\microsoft.build.16.3.0\lib\net472\Microsoft.Build.dll</HintPath>
    <Private>True</Private>
  </Reference>
</ItemGroup>

but not just this:

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
  <PackageReference Include="Microsoft.Build" Version="16.3.0" />
</ItemGroup>

Thanks,

// From 2015 (who remember me here) we're still actively using other ways with nuget packages due to some incomprehensible things like above.

And looks like I personally still will use my portable GetNuTool together with vsSolutionBuildEvent scripts. Just because this all works fine <_<

NuGet Package Manager 5.2.0
VisualStudio.16.Release/16.2.2+29209.62
NuGet Package Manager 4.6.0
VisualStudio.15.Release/15.9.16+28307.858
donnie-msft commented 5 years ago

Where did your PackageReferences come from (generated or manual) ? Pinging @nkolev92 , as I'm not the expert here.

FYI, here's what I tried without any issue:

Firstly, Microsoft.Build 15.9.20 depends on NETStandard 2.0.

And I had no issue adding this to my csproj:

 <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
    <PackageReference Include="Microsoft.Build" Version="15.9.20" />
  </ItemGroup>

Which generated this project.assets.json as expected:

 "ClassLibrary1/1.0.0": {
        "type": "project",
        "framework": ".NETStandard,Version=v2.0",
        "dependencies": {
          "Microsoft.Build": "15.9.20"
        },
        "compile": {
          "bin/placeholder/ClassLibrary1.dll": {}
        },
        "runtime": {
          "bin/placeholder/ClassLibrary1.dll": {}
        }
      }
3F commented 5 years ago

@donnie-msft Thank you for reply!

The problem exactly with other versions. As it was shown in my samples above.

I need to provide netstandard1.1 target platform if we will talk about more specific problem.

Today I still can't through PackageReference at all. Only for old Reference this is possible as you can see. Or try it by my examples from MvsSln or here above.

And this is it, Why in the nuget world only identical (according to the minimal version) target platforms are allowed?

Where did your PackageReferences come from (generated or manual) ?

manual.

But initially I was checking via package manager inside VS IDE if you ask.

3F commented 5 years ago

Here is a complete example for your convenience.

Through PackageReference - FAILED :

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard1.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Build" Version="15.9.20" />
  </ItemGroup>

</Project>
D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3>dotnet build
Microsoft (R) Build Engine version 16.2.32702+c4012a063 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\ClassLibrary3.csproj : error NU1202: Package Microsoft.Build 15.9.20 is not compatible with netstandard1.1 (.NETStandard,Version=v1.1). Package Microsoft.Build 15.9.20 supports:
D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\ClassLibrary3.csproj : error NU1202:   - net46 (.NETFramework,Version=v4.6)
D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\ClassLibrary3.csproj : error NU1202:   - netcoreapp2.1 (.NETCoreApp,Version=v2.1)
D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\ClassLibrary3.csproj : error NU1202:   - netstandard2.0 (.NETStandard,Version=v2.0)
  Restore failed in 252.57 ms for D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\ClassLibrary3.csproj.

Build FAILED.

Through Reference - Build succeeded:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard1.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <HintPath>..\packages\microsoft.build.15.9.20\lib\net46\Microsoft.Build.dll</HintPath>
      <Private>True</Private>
    </Reference>

    <!-- MSB3277 -->
    <Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <HintPath>..\packages\system.io.compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
      <Private>True</Private>
    </Reference>
  </ItemGroup>

</Project>
D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3>dotnet build
Microsoft (R) Build Engine version 16.2.32702+c4012a063 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 48.3 ms for D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\ClassLibrary3.csproj.
  ClassLibrary3 -> D:\tmp\_Issues\MvsSln\netstd\ClassLibrary3\ClassLibrary3\bin\Debug\netstandard1.1\ClassLibrary3.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)
nkolev92 commented 5 years ago

Through PackageReference - FAILED :

The package Microsoft.Build, 15.9.20 supports the following platofrms:

netcoreapp21 netstandard20 net46

Your project is netstandard11.

None of the package frameworks are compatible with netstandard11, so that's why the PackageReference install fails.

See https://nugettoolsdev.azurewebsites.net/5.3.0/framework-compatibility?project=netstandard1.1&package=netstandard2.0 for example.

Through Reference - Build succeeded:

Are you adding those references manually? Then you are merely bypassing NuGet's compatibility checks and there's no guarantee that your project will work at runtime.

Why is your project framework .NET Standard 1.1?

3F commented 5 years ago

Then you are merely bypassing NuGet's compatibility checks and there's no guarantee that your project will work at runtime.

I fully understand this subset. I'm only describing the difference between coreclr impl and nuget restriction!

For example:

<PackageReference Include="Microsoft.Build" Version="16.3.0" />
error NU1202: Package Microsoft.Build 16.3.0 is not compatible with netstandard2.0 (.NETStandard,Version=v2.0). Package Microsoft.Build 16.3.0 supports:
error NU1202:   - net472 (.NETFramework,Version=v4.7.2)
error NU1202:   - netcoreapp2.1 (.NETCoreApp,Version=v2.1)

YES, technically API layer in netstandard2.0 is not complete for netcoreapp2.1 implementation. But my question still is not about this.

Moreover, in my example above I'm sure this will work at least for X components without problems after manual MSB3277 fixes.

I mean, it will be useful to be able to solve problems manually like for classical Reference. However, as I understand, NuGet today still just drops any possible use through PackageReference. This is what I'm talking about.

What about 16.3.0? just netcoreapp2.1. That is, I can't even for netstandard2.0. Microsoft.Build is just for good example. But this is not only about it.

Why is your project framework .NET Standard 1.1?

Because this is optimal for other related dependencies in today's MvsSln and its related projects.

nkolev92 commented 5 years ago

Moreover, in my example above I'm sure this will work at least for X components without problems after manual MSB3277 fixes.

It's pure luck if it does work. You likely have a runtime that's net46 or higher.

Because this is optimal for other related dependencies in today's MvsSln and its related projects.

Then you should not take dependencies to assemblies that require higher versions of the framework. You will run into runtime problems at some point.

What about 16.3.0? just netcoreapp2.1. That is, I can't even for netstandard2.0. Microsoft.Build is just for good example. But this is not only about it.

That's up to the publisher of the Microsoft.Build package. They only work against the specified framework, it's on them to decide which frameworks their libraries need.

Unfortunately I'm not sure what the question is here.

The compatibility tree you are effectively building will lead to runtime failures at some point. PackageReference and NuGet in general (even packages.config will do the same thing if you try to install the package), will not allow this to happen. It's NuGet's job to not put consumers in situations where their projects will fail. Reference simply does not have as many validations as bringing a package through NuGet does.

3F commented 5 years ago

Then you should not take dependencies to assemblies that require higher versions of the framework.

net472 -to-> netstandard2.0 ? okay

That's up to the publisher of the Microsoft.Build package.

Yes, of course +lot of other pkgs. Btw, just remembered this: https://github.com/microsoft/msbuild/issues/3581

It's NuGet's job to not put consumers in situations where their projects will fail.

Yeah, thanks again for my additional hours with an urgent fixes in our internal projects like for this and more: https://github.com/NuGet/Home/issues/1521

Reference simply does not have as many validations as bringing a package through NuGet does.

This is other story. I'm talking about this layers. And let's think for a moment when I will try to use local references together with nuget.

Unfortunately I'm not sure what the question is here.

The question was about difference in implementing restrictions. Or okay, just the Ways to solve specific targets manually via PackageReference (options to ignore nu1202 or to force re-targeting).

Unfortunately after almost 5 years I'm still sure for a vsSolutionBuildEvent and GetNuTool projects (that was appeared just to solve your "to not put consumers") at least for the cases like this.

3F commented 5 years ago

An addition to related issue about partial compatibility of the dependencies that I also already mentioned here:

for projects below, the following direct reference are not needed. But NuGet dependency policy will add this anyway: https://github.com/dependabot/feedback/issues/259#issuecomment-508242665

Because if you really know what are you doing, you can even reduce some required references from you assembly while the dependent library will still reference even missing modules like dlls.

For projects such as vsSolutionBuildEvent it also adds lot of inconvenience to review and merge 100+ dep pkgs. But this is other issue. Just about incompatible ways for our compatibility.

nkolev92 commented 5 years ago

net472 -to-> netstandard2.0 ? okay

That's ok, but you don't seem to be doing this. Your example has netstandard as the pivot and netstandard1.1 to net46 is not ok.

This is other story. I'm talking about this layers. And let's think for a moment when I will try to use local references together with nuget.

Can you be more specific what about the layers you have issues with? NuGet implements that specific table in its framework compatibility checks.

The question was about difference in implementing restrictions. Or okay, just the Ways to solve specific targets manually via PackageReference (options to ignore nu1202 or to force re-targeting).

Reference has been around for a very long time, way before NuGet was ever a thing. Ignoring NU1202 is not the right approach. NuGet cannot force anyone to retarget, but rather it merely spits out an error message saying why it could not resolve.

I apologize, I'm not sure what the overall ask is. :(

In the original part of the issue, you said NuGet does not allow you to match netstandard1.1 to net46,netcoreapp21, netstandard20 and that's expected. The NU1202 is warranted in this case.

3F commented 5 years ago

That's ok, but you don't seem to be doing this.

above

error NU1202: Package Microsoft.Build 16.3.0 is not compatible with netstandard2.0 (.NETStandard,Version=v2.0). Package Microsoft.Build 16.3.0 supports:
error NU1202:   - net472 (.NETFramework,Version=v4.7.2)
error NU1202:   - netcoreapp2.1 (.NETCoreApp,Version=v2.1)

Microsoft.Build 16.3.0 is not compatible with netstandard2.0

-> NU1202: - net472

nkolev92 commented 5 years ago

It seems like I missed it, sorry about that.

Now the package supports:

net472 and netcoreapp2.1

Both of those implement netstandard2.0, but they both have a wider set of APIs available as you said yourself.

netstandard2.0 is not compatible with net472 and netcoreapp2.1. The reverse is true, but not in that direction. https://nugettoolsdev.azurewebsites.net/5.3.0/framework-compatibility?project=netstandard2.0&package=net472.

Now, this mapping specifically is not a perfect match so NuGet will raise an error for every such incompatibility encountered.

In certain cases, NuGet allows authors to provide a fallback framework to get a partial match if possible. NuGet does not own this mapping, it's merely a fallback.

In .NET Core SDK 2.2400 the fallback from netstandard2.0 was net461 In .NET Core sdk 3.0.100, the fallback from netstandard2.0, is now all of the .NET Frameworks.

So if you install the latest SDK you would get the following:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <RootNamespace>_8644</RootNamespace>
  </PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.Build" Version="16.3.0" />
</ItemGroup>

</Project>
F:\test\8644> dotnet restore
F:\test\8644\8644.csproj : warning NU1701: Package 'Microsoft.Build 16.3.0' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETStandard,Version=v2.0'. This package may not be fully compatible with your project.
  Restore completed in 1.39 sec for F:\test\8644\8644.csproj.

Hope this clears it up. Note that this is a fallback and that's why NU1701 is raised in this case. You still might have runtime issues.

dasMulli commented 5 years ago

There seems to be confusion around the "X to Y" reference.

.NET 4.7.2 projects "can use" netstandard2.0 assemblies. However, it is not the other way around.

Same for .NET Core 2.1. Both .NET Core 2.1 and .NET 4.7.2 contain more APIs than defined in .NET Standard 2.0, so a .NET Standard 2.0 project cannot use a .NET 4.7.2 or .NET Core 2.1 project/library. (There is a the mentioned fallback workaround for .NET Framework that is dangerous but possible, but will not work for most of MSBuild since it relies on app domains for the .NET Framework part)

Microsoft.Build was explicitly moved to .NET 4.7.2 to be in line with Visual Studio and the .NET Standard part was replaced with a .NET Core specific part to be able to use newer APIs to help with build times.

3F commented 5 years ago

Sounds like something secret o_0

I don't see problems say for netfx -> netstandard-> netfx ...

Because in general, netstandard it's just ~API. Layer between specific impl.

.NET 4.7.2 projects "can use" netstandard2.0 assemblies.

Yes, of course, because netstd2 covers 472

However, it is not the other way around.

I already mentioned the possible ways above. But if you need again my full example, I'll try tomorrow. just /2 AM on my watch

nkolev92 commented 5 years ago

I think the focus should be on:

However, it is not the other way around. I already mentioned the possible ways above.

What you've shown us are sort of "hacks" where we cannot guarantee no runtime problems.

When restoring netstandard => netfx, NuGet cannot know that it will later be referenced again by netfx, and it might just end up working by accident.

What if NuGet allows netstandard => netfx reference where later that package gets referenced by netcoreapp? Then the runtime would have issues.

There are scenarios where the customer and other tooling are aware of the risks and are willing to take them, so that's why AssetTargetFallback exists and that's why .NET Core 3.0 behaves in the way I suggested earlier.

I think I finally understand your scenario, and .NET Core 3.0 SDK already accounts for that.

donnie-msft commented 5 years ago

Today I still can't through PackageReference at all. Only for old Reference this is possible as you can see.

Perhaps some confusion here is from the fact that References have no validation applied to them. They sometimes accidentally work, even if they aren't explicitly compatible. You may or may not have a runtime error (you are lucky in that you're not having a runtime error).

PackageReference are always validated for TFM compatibility. Thus, you're seeing the error only when using references this way.

3F commented 5 years ago

Perhaps some confusion here is from the fact that References have no validation applied to them

That's what I was talking about initially. If user still can reference something locally, Why not to provide additional options to be closer to CLR features.

You may or may not have a runtime error (you are lucky in that you're not having a runtime error).

A rocket science in action.

I think I finally understand your scenario,

It seems like. However, it would be nice to have an additional option for manual routes at some specific cases. Just as I said initially.

What you've shown us are sort of "hacks"

I understand your "job to not put consumers" and position with "hacks" because it really may be a big problem for common users. But again, sometimes these can be are a very important hacks like this https://github.com/3F/DllExport

And anyway, "to not put consumers" will never work for 100%. While the any options will just delegates responsibility to the end user.

and .NET Core 3.0 SDK already accounts for that.

I still did not look closer the just released .net core 3. Later I will look into together with important tasks for .NET DllExport. Looks like already soon. Hello to everyone who is still waiting for it. Almost ready to start review.

nkolev92 commented 5 years ago

because it really may be a big problem for common users.

AssetTargetFallback is the solution for not 100% compatible framework. It's something that can be provided by the user or otherwise.

Note that it's not recommended to stray away from the NuGet/SDK imposed restrictions, because if you end up shipping a package that bypasses NuGet/SDK restrictions it might not work for your customers and the tooling would not be able to tell that.

In the .NET Core 3.0 SDK there's a fallback that allows the selection of such assets, but they are not guaranteed to work, so that's why you get a warning.

Note that even the fallbacks are one studied and determined as "likely to work".

netstandard2.0 falling back to net461 is likely to work. netstandard1.1 to net461 will most likely not.

I'd suggest you try the .NET Core 3.0 SDK. :)

And anyway, "to not put consumers" will never work for 100%. While the any options will just delegates responsibility to the end user.

And you can bypass that by setting AssetTargetFallback at your own risk, but consider the risks if you end up shipping that project as a package, that the consumers' machines will not have the same compatibility mappings you did when you built the project. Your package might not even install. :)

Anyway, I'm marking this as a question, as I do not believe a change in the product is warranted here. This is by design and we believe AssetTargetFallback gives customers enough control if need be. Carefully consider if you end up publishing a package with a non-NuGet/SDK specified AssetTargetFallback.

3F commented 5 years ago

Thanks for clarifying my question! I understood NuGet team with this issue, and partially(yet) I support it.

try the .NET Core 3.0 SDK

We will :) It was planned anyway.