ERROR!
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.TargetFrameworkInference.targets(84,5): error : Cannot infer TargetFrameworkIdentifier and/or TargetFrameworkVersion from TargetFramework='portable-net40+sl5+win8+wpa81+wp8'. They must be specified explicitly. 1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1111,5): error MSB3644: The reference assemblies for framework ".NETFramework,Version=v0.0" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.
In the Microsoft.NET.TargetFrameworkInference.targets
file it helpfully says this:
<!-- Note that this file is only included when $(TargetFramework) is set and so we do not need to check that here. Common targets require that $(TargetFrameworkIdentifier) and $(TargetFrameworkVersion) are set by static evaluation before they are imported. In common cases (currently netstandard, netcoreapp, or net), we infer them from the short names given via TargetFramework to allow for terseness and lack of duplication in project files. For other cases, the user must supply them manually. For cases where inference is supported, the user need only specify the targets in TargetFrameworks, e.g: <PropertyGroup> <TargetFrameworks>net45;netstandard1.0</TargetFrameworks> </PropertyGroup> For cases where inference is not supported, identifier, version and profile can be specified explicitly as follows: <PropertyGroup> <TargetFrameworks>portable-net451+win81;xyz1.0</TargetFrameworks> <PropertyGroup> <PropertyGroup Condition="'$(TargetFramework)' == 'portable-net451+win81'"> <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier> <TargetFrameworkVersion>v4.6</TargetFrameworkVersion> <TargetFrameworkProfile>Profile44</TargetFrameworkProfile> </PropertyGroup> <PropertyGroup Condition="'$(TargetFramework)' == 'xyz1.0'"> <TargetFrameworkIdentifier>Xyz</TargetFrameworkVersion> <PropertyGroup> Note in the xyz1.0 case, which is meant to demonstrate a framework we don't yet recognize, we can still infer the version of 1.0. The user can also override it as always we honor a TargetFrameworkIdentifier or TargetFrameworkVersion that is already set. -->
In a project, I was targeting: net45
netstandard1.3
and .NETPortable,Version=v4.0,Profile=Profile328
The auto migration only does so far:
net45;netstandard1.3;portable40-net40+sl5+win8+wp8+wpa81
There are some other properties added for portable40-net40+sl5+win8+wp8+wpa81
but the end result is that on build, MSBuild doesn’t know what portable40-net40+sl5+win8+wp8+wpa81
means.
To fix this, translate Profile328
to what the comments say from the targets file. I also used this from Microsoft as a guide for profile targets.
I added:
<PropertyGroup Condition="'$(TargetFramework)' == 'portable-net40+sl5+win8+wpa81+wp8'"> <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkProfile>Profile328</TargetFrameworkProfile> </PropertyGroup>
The name portable-net40+sl5+win8+wpa81+wp8
could be anything really as long as they match and the above XML really puts the profile, version and identifer for MSBuild.
Here’s the complete working csproj
Why couldn’t migrate do this for you? I don’t know.