Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtimeconfig.json contains incorrect framework version #686

Closed
natemcmaster opened this issue Jan 19, 2017 · 12 comments · Fixed by #820
Closed

runtimeconfig.json contains incorrect framework version #686

natemcmaster opened this issue Jan 19, 2017 · 12 comments · Fixed by #820

Comments

@natemcmaster
Copy link
Contributor

natemcmaster commented Jan 19, 2017

Repro:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NETCore.App" Version="2.0.0-beta-001382-00" />
  </ItemGroup>

</Project>
<configuration>
    <packageSources>
        <add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
    </packageSources>
</configuration>

dotnet restore
dotnet build

Expected
lib/Debug/netcoreapp2.0/myapp.runtimeconfig.json should contain

{
  "runtimeOptions": {
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "2.0.0-beta-001382-00"
    }
  }
}

Actual

{
  "runtimeOptions": {
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "2.0.0"
    }
  }
}

Details
Using CLI: 1.0.0-rc3-004517

Happens even when <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences> is added.

@dasMulli
Copy link
Contributor

This one works for me:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <RuntimeFrameworkVersion>2.0.0-beta-001382-00</RuntimeFrameworkVersion>
    <NetCoreAppImplicitPackageVersion>$(RuntimeFrameworkVersion)</NetCoreAppImplicitPackageVersion>
  </PropertyGroup>
</Project>

Best documentation seems to be the comment by @dsplaisted

@srivatsn
Copy link
Contributor

Yes RuntimeFrameworkVersion is what gets put into runtimeconfig.json and it is inferred based on the TFM with the idea that hostpolicy would roll forward to the latest path version installed.

@natemcmaster
Copy link
Contributor Author

natemcmaster commented Jan 19, 2017

runtimeconfig version should contain the resolved package version of Microsoft.NETCore.App. Inferring the version from TFM is too naïve: it doesn't account for:

  • the runtimeOption "applyPatches": false which disables rollforward
  • hostpolicy does not roll forward across minor versions. Currently, a package reference to Microsoft.NETCore.App 1.1.0 and project TFM set to netcoreapp1.0 produces runtimeconfig with 1.0.0, but should be 1.1.0.
  • hostpolicy does not roll forward from pre-release versions to stable versions
  • user intent to upgrade to new patches. Currently, a package reference to Microsoft.NETCore.App 1.0.3 produces runtimeconfig with 1.0.0, but should be 1.0.3.
  • visibility in NuGet GUI in 'Update' section
  • package references with floating versions of Microsoft.NETCore.App (e.g. 2.0.0-*)
  • side effects on how deps.json is trimmed from project.assets.json based on the resolved version of Microsoft.NETCore.App

@dasMulli
Copy link
Contributor

Currently, a package reference to Microsoft.NETCore.App 1.1.0 and project TFM set to netcoreapp1.0 produces runtimeconfig with 1.0.0, but should be 1.1.0.

Isn't 1.0.* correct here? The 1.1.0 NuGet package contains different references for netcoreapp1.0 and netcoreapp1.1 so you can actually target .net core 1.0 and use the latest package anyway.

@natemcmaster
Copy link
Contributor Author

natemcmaster commented Jan 19, 2017

Isn't 1.0.* correct here?

If the intent is to preserve how project.json built and run, then no, current implementation is wrong. Ms.NETCore.App 1.1.0 + netcoreapp1.0 TFM in project.json produces 1.1.0 in the runtimeconfig.json file.

If the intention is to change this behavior of project.json, then dotnet-migrate needs to be made aware of this or it should be an error to reference 1.1.0 package in the netcoreapp1.0 TFM. Otherwise, projects will start running on .NET Core 1.0 instead of 1.1 after upgrading. cc @piotrpMSFT @livarcocc

@dasMulli
Copy link
Contributor

Ms.NETCore.App 1.1.0 + netcoreapp1.0 TFM in project.json produces 1.1.0 in the runtimeconfig.json

So it possibly compiles against the 1.0.* assemblies and runs on 1.1.0? That seems weird.. especially when you can explicitly select .net core 1.0 from UI dialogs now..
So if I explicitly target 1.0 and then run on a host that only has 1.0.*, I will get an error because I accidentally did the "update all" via NuGet UI? 😱

@natemcmaster
Copy link
Contributor Author

Removing 'Blocking partner' label. We unblocked ourselves by adding custom targets to set RuntimeFrameworkVersion based on the package version of Microsoft.NETCore.App instead of TFM, but IMO this is still a serious bug that we should fix by RTM.

natemcmaster pushed a commit to aspnet/BuildTools that referenced this issue Jan 19, 2017
…, not TFM

Workaround dotnet/sdk#686

Also, fix casing of the serviceable assembly attribute
@muratg
Copy link

muratg commented Jan 19, 2017

Keeping blocking Partner label, as we'd like to remove workarounds for RTM.

@NTaylorMullen
Copy link
Contributor

NTaylorMullen commented Jan 20, 2017

This causes some pretty awful side effects for semi-complex test projects. If you happen to utilize a type in a Microsoft.NETCore.App that doesn't match the one in runtimeconfig.json then dotnet test fails to run and exits with:

Microsoft (R) Test Execution Command Line Tool Version 15.0.0.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
Error: Failed to initialize client proxy: could not connect to test process.

Overall horribad for end-users.

For those curious, associated bug from vstest to flow error messages better: microsoft/vstest#281

@dsplaisted
Copy link
Member

The intent of how this works is:

  • There isn't a PackageReference to Microsoft.NETCore.App explicitly in your project file
  • You specify the version of .NET Core to target via the TargetFramework attribute, ie netcoreapp1.0 or netcoreapp1.1
  • If you want to target a specific patch version, or a prerelease version, you do that by setting the RuntimeFrameworkVersion property

The logic for how this works is described here. Basically:

  • If the TargetFramework is some version of netcoreapp, then there will be an implicit PackageReference to Microsoft.NETCore.App
  • By default the version of Microsoft.NETCore.App referenced is 1.1.0. This NuGet package has the references for both 1.0.0 and 1.1.0, so it should give you the correct APIs for either version
  • By default, the framework version written to runtimeconfig.json comes from the version specified in the TargetFramework property
  • However, if the RuntimeFrameworkVersion property is specified, then that version will be used for the implicit package reference to Microsoft.NETCore.App as well as the version written out in the runtimeconfig.json file

I think this addresses most of the issues raised. From @natemcmaster's list:

  • the runtimeOption "applyPatches": false which disables rollforward
  • hostpolicy does not roll forward across minor versions. Currently, a package reference to Microsoft.NETCore.App 1.1.0 and project TFM set to netcoreapp1.0 produces runtimeconfig with 1.0.0, but should be 1.1.0.
  • hostpolicy does not roll forward from pre-release versions to stable versions

If roll-forward is disabled, then you can specify a specific patch version with the RuntimeFrameworkVersion property. @natemcmaster, does that address these issues?

  • user intent to upgrade to new patches. Currently, a package reference to Microsoft.NETCore.App 1.0.3 produces runtimeconfig with 1.0.0, but should be 1.0.3.

Some users understood what the PackageReference version meant, but others were confused about the difference between the target framework version and package version. Others would update all their packages to the the latest versions in the NuGet UI and this would break their projects (see #493, #501, and dotnet/corefx#14696). So we're saying that now you don't deal with package references to specify the patch version, you use the RuntimeFrameworkVersion property.

  • visibility in NuGet GUI in 'Update' section

We would like to hide updates to the implicitly referenced packages from the NuGet UI, or not show them in that UI at all. I believe we are planning to do this for RTM.

  • package references with floating versions of Microsoft.NETCore.App (e.g. 2.0.0-*)

This isn't well supported currently. Who outside of Microsoft would you expect to want to float the version of Microsoft.NETCore.App used?

  • side effects on how deps.json is trimmed from project.assets.json based on the resolved version of Microsoft.NETCore.App

Microsoft.NETCore.App should be (and I believe it is) authored so that if you are targeting netcoreapp1.0, then the 1.1.0 and 1.0.x versions of the package will give you get the same references, assets, etc. So I don't think there are side effects based on this.

If the intention is to change this behavior of project.json, then dotnet-migrate needs to be made aware of this

We have dotnet/cli#5346 for dotnet-migrate to handle this correctly.

We unblocked ourselves by adding custom targets to set RuntimeFrameworkVersion based on the package version of Microsoft.NETCore.App

Generally this should be the other way around: Just set the RuntimeFrameworkVersion property and the package version will be implied from that. If you are trying to float the package version I can see that it's not that simple though.

@NTaylorMullen

This causes some pretty awful side effects for semi-complex test projects. If you happen to utilize a type in a Microsoft.NETCore.App that doesn't match the one in runtimeconfig.json then dotnet test fails to run and exits with ...

If I'm understanding correctly, I think that this is improved with the current behavior. In RC1 or RC2, we had a bunch of people that upgraded the Microsoft.NETCore.App package to 1.1.0, and their project then failed to run because it now depended on the 1.1 runtime, which wasn't installed. They didn't realize that upgrading the package had that effect. This sounds similar to the test issue you linked to. Now people generally won't be accidentally taking a dependency on a new version of the runtime in their projects. It also helps that the tooling is now going to include both versions 1.0 and 1.1 of the runtime.

@BladeWise
Copy link

BladeWise commented Jan 30, 2017

I understand the rationale behind these changes, yet at the moment projects that ran without issues in RC2, simply do not, throwing this error:

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

The overall experience is not really satisfying... Consider this example, that worked fine in RC2:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Update="Microsoft.NETCore.App" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.2.0-*" />
  </ItemGroup>
</Project>

I am creating a console application targeting some pre-release versions that require Microsoft.NETCore.App 1.2.0 (as far as I can tell). Before RC3, I would simply bump the package reference and, provided that the correct sdk/runtime was installed, everything would work. I the correct runtime was not present, VS would simply fail to run the application, but using dotnet run would actually prompt the list of installed runtimes stating that required one was missing.

If we use the same approach now, no warning is issued and the application fails to run.
Without a proper migration document I made some attempts, using bits and pieces found in various issues reported.

Using DisableImplicitFrameworkReferences (in existing projects I received a warning regarding duplicated references to the Microsoft.NETCore.App) like this

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <DisableImplicitFrameworkReferences>True</DisableImplicitFrameworkReferences>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Update="Microsoft.NETCore.App" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.2.0-*" />
  </ItemGroup>
</Project>

produces the following result:

A fatal error was encountered. The library 'hostpolicy.dll' required to execute the application was not found in 'C:\Users\d.mancini\Documents\Visual Studio 2017\Projects\ClassLibrary1\ConsoleApp2\bin\Debug\netcoreapp1.1'.

Using the NetCoreAppImplicitPackageVersion like this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <NetCoreAppImplicitPackageVersion>1.2.0-*</NetCoreAppImplicitPackageVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.2.0-*" />
  </ItemGroup>
</Project>

does not complain during compilation, but project still fails to run with aforementioned error.

Finally, thanks to the details in these comments, I could produce a working solution:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <RuntimeFrameworkVersion>1.2.0-beta-001304-00</RuntimeFrameworkVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.2.0-*" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.2.0-*" />
  </ItemGroup>
</Project>

but this is definitely not intuitive, since I have no error to determine which runtime I should actually specify.

Moreover, consider that RC3 still allows to update Microsoft.NETCore.App, producing a project that compiles fine but cannot run.

@natemcmaster
Copy link
Contributor Author

Re @dsplaisted:

I'm on board with the UX goals you described. But the current implementation is buggy.

Who outside of Microsoft would you expect to want to float the version of Microsoft.NETCore.App used?

Anyone wanting to build nightlies on .NET Core. @BladeWise is at least one. I'm sure there are more.

side effects on how deps.json is trimmed from project.assets.json based on the resolved version of Microsoft.NETCore.App

Microsoft.NETCore.App should be (and I believe it is) authored so that if you are targeting netcoreapp1.0, then the 1.1.0 and 1.0.x versions of the package will give you get the same references, assets, etc. So I don't think there are side effects based on this.

Actually, we saw a real-life example of this side effect. We referenced Microsoft.NETCore.App 1.2.0-* on netcoreapp1.1 TFM. Because deps.json is trimmed from project.assets.json our tests failed to run with this error: "System.IO.FileLoadException: Could not load file or assembly 'System.Diagnostics.TraceSource'". This happened because Microsoft.NETCore.App 1.2.0 introduced changes to package references.

I expect this will continue to break in unexpected ways as deps.json dependency trimming is based on NuGet package resolution (...which is again, based on the resolved Microsoft.NETCore.App package version).

hostpolicy does not roll forward from pre-release versions to stable versions

This will be an issue when we want to release Microsoft.NETCore.App 2.0.0-preview1. It is okay to infer PackageReference version from TFM, but not okay to infer runtimeconfig version from TFM.

mmitche pushed a commit to mmitche/sdk that referenced this issue Jun 5, 2020
…604.23 (dotnet#686)

- Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19304.23
DotDeveloper95 added a commit to DotDeveloper95/BuildTools that referenced this issue Sep 4, 2023
…, not TFM

Workaround dotnet/sdk#686

Also, fix casing of the serviceable assembly attribute
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment