sdk: Multi framework targetting not working with VS2017 RC

Steps to reproduce

  • Install Visual Studio 2017 RC with .NET Core support.
  • Create a new .NET Core project. Type seemingly does not matter, tested with Web MVC and Console application.
  • Right click on project in Solution Explorer and select “Edit name.csproj
  • Find the line with the TargetFramework element.
  • Replace netcoreapp1.0 with netcoreapp1.0;net452, as demonstrated in this .NET Blog post under the section Cross-targeting.

Expected behavior

  • Project compiles for both netcoreapp1.0 and net452 as previously with the project.json format.

Actual behavior

Error occurs:

MSB4115 The "HasTrailingSlash" function only accepts a scalar value, but its argument "$(OutputPath)" evaluates to "bin\Debug\netcoreapp1.0;net452\" which is not a scalar value.

Environment data

dotnet --info output:

.NET Command Line Tools (1.0.0-preview3-004056)

Product Information:
 Version:            1.0.0-preview3-004056
 Commit SHA-1 hash:  ccc4968bc3

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.14393
 OS Platform: Windows
 RID:         win10-x64

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 1
  • Comments: 18 (7 by maintainers)

Most upvoted comments

My suggestion is to remove the distinction. Why have two element names for a single purpose? It just adds unnecessary complexity. The new format is supposed to be simplified.

@MartinJohns

The original issue was definitely using TargetFramework to specify multiple frameworks instead of TargetFrameworks (plural). The blog post has that right.

There are two other issues:

  1. Currently, you do need to specify a RuntimeIdentifier if one of your targets is the full .NET Framework and you are building an exe. We are looking to improve this, see https://github.com/dotnet/sdk/issues/396

  2. You must condition the .NETCoreApp package reference to only the netcoreapp1.0 build as the package is not compatible with net452. This is also being improved with https://github.com/dotnet/sdk/pull/450 which will make the package ref implicit and remove you from having to condition it yourself.

(1) above explains the RuntimeIdentifier error you’re seeing. (2) might be the “invalid restore input” you’re seeing, but I’m seeing much clearer nuget errors on newer than RC bits:

    One or more packages are incompatible with .NETFramework,Version=v4.5.2.
    Package Microsoft.NETCore.App 1.0.1 is not compatible with net452 (.NETFramework,Version=v4.5.2).

For (1), here is how the main property group should look with both RuntimeIdentifer and TargetFrameworks set:

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp1.0;net452</TargetFrameworks>
    <RuntimeIdentifier>win7-x86</RuntimeIdentifier>
  </PropertyGroup>

For (2), here is how the NETCore.App package ref should be conditioned

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0'">
    <PackageReference Include="Microsoft.NETCore.App">
      <Version>1.0.1</Version>
    </PackageReference>
  </ItemGroup>

Let me know if you’re still seeing errors after applying the above and please share the full .csproj that isn’t working for you.

Ignoring the name confusion, let’s imagine we remove the concept of “TargetFramework”, what condition would you write to have an item (say a package or project reference) only apply to a single framework?

@SzymonSasin After that I was able to compile, and start server (dotnet run) but it collapsed after http request.

Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/  
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action method MyReduxProject.Controllers.HomeController.Index (MyReduxProject) with arguments ((null)) - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1]
      Executing ViewResult, running view at path /Views/Home/Index.cshtml.
info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
      User profile is available. Using 'C:\Users\roman\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action MyReduxProject.Controllers.HomeController.Index (MyReduxProject) in 4022.9624ms
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
      An unhandled exception has occurred: Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
System.IO.FileLoadException: Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
<TargetFramework>net462</TargetFramework>
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>

Hey @nguerrera,

I’ve indeed overlooked that there’s a plural version in the blog post. Performing the changes that you mentioned allowed me to compile the project. But the way to this has been very rocky - I think the mistakes I made are very easily done and the tooling should at least inform me about solutions to the most common mistakes. That there’s no schema (after the latest VS update) doesn’t help much, and the XML editing experience is not great either (e.g. when I rename an opening tag it doesn’t rename the closing tag).

Here’s my updated csproj file:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp1.0;net452</TargetFrameworks>
    <RuntimeIdentifier>win7-x86</RuntimeIdentifier>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="**\*.cs" />
    <EmbeddedResource Include="**\*.resx" />
  </ItemGroup>
  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0'">
    <PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
  </ItemGroup>
</Project>

It compiles fine, but when I press F5 I get the following error: “Unable to run your project. The “RunCommand” property is not defined.”

Executing the net452 version works. Trying to execute the netcoreapp1.0 version fails:

C:\ConsoleApp2\bin\Debug\netcoreapp1.0>dotnet ConsoleApp2.dll
Could not find required library hostpolicy.dll in 1 probing paths:
  C:\Users\Martin\.nuget\packages
A fatal error was encountered. The library 'hostpolicy.dll' required to execute the application was not found in 'C:\ConsoleApp2\bin\Debug\netcoreapp1.0'.

Any advice on this?

Additionally, can you please expand on these questions?

  • How to define multiple RuntimeIdentifier? Yes, I’ve tried RuntimeIdentifiers. 😃
  • How to adjust the project file to retrieve a standalone netcoreapp version?
  • How to tell Visual Studio 2017 RC which target framework I currently want to develop for (switch between intellisense for net452 and netcoreapp1.0)?

I guess the suggestion here is to add a better error message? If so, this should be tracked in dotnet/sdk, since that is where the errors for this would come from.

The migration to MSBuild XML schema only give to us bad user experience, i not like vs2017… i prefer vs2015 with json project format, easy and friendly. Nobody try to learn MSBuild schema before… the people are trying to do the things like with json project format and MSBuild is ugly.

I agree this is rocky and I apologize for that. FWIW, cross-targeting exe projects is significantly more complicated by these RID issues than cross-targeting libraries. We still need to do better on the docs and diagnostics, but let me try to answer your questions here.

Executing the net452 version works. Trying to execute the netcoreapp1.0 version fails:

The failure to load hostpolicy.dll is because we set an x86 RID for all outputs and we’re trying to run on x64 dotnet.

Additionally, can you please expand how to define multiple RuntimeIdentifier? Yes, I’ve tried RuntimeIdentifiers. :-

For defining multiple RIDs, nuget restore understands RuntimeIdentifiers (plural), but everything else requires that you specify one at a time. There is https://github.com/dotnet/sdk/issues/414 to reconcile this but in the meantime, you can get to a state that works for this project by specifying the full set of RIDs statically for restore and only setting a single RID when you’re actually building for desktop.

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp1.0;net452</TargetFrameworks>
    <RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
  </PropertyGroup>
  <PropertyGroup Condition="'$(TargetFramework)' == 'net452'">
    <!-- We must pick a single RID for desktop in order to consume native libraries. -->
    <RuntimeIdentifier>win7-x86</RuntimeIdentifier>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="**\*.cs" />
    <EmbeddedResource Include="**\*.resx" />
  </ItemGroup>
  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0'">
    <PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
  </ItemGroup>
</Project>

From there:

  • Restore

dotnet restore

  • Build for all target frameworks

dotnet build

  • Run on desktop

dotnet run --framework net452

  • Run on core clr

dotnet run --framework netcoreapp1.0

  • Publish .NET Core standalone app for win7-x64

dotnet publish --framework netcoreapp1.0 --runtime win7-x64