In VS2017 it much easier now to support multiple frameworks inside a single .csproj file.
When you create a new project VS2017 (that target .NET Core or .NET Standard) this is what you’ll get inside your *.csproj
1 2 3 4 5 6 7 | < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFramework >netstandard1.4</ TargetFramework > </ PropertyGroup > </ Project > |
Cool right? A lot of the boilerplate configuration was removed in order to make the MSBuild format clean and readable.
By default, all the files inside your project folder will be added. If you want to make adjustment you can always add (or remove some of the files).
For example, this is how it will look if I want to explicitly add the Properties folder to my project but exclude the AssemblyInfo.cs file.
1 2 3 4 5 6 7 8 9 10 11 | < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFramework >netstandard1.4</ TargetFramework > </ PropertyGroup > < ItemGroup > < Folder Include = "Properties\" /> < Compile Remove = "Properties\AssemblyInfo.cs" /> </ ItemGroup > </ Project > |
Target Framework Moniker TFM
The new MSBuild format support declaration of multiple framework targets inside the same property group. If you need you library to support .NET 4.0, .NET 4.5, .NET Standard 1.6 and .NET Core 1.1, the only change you need to make is to change TargetFramework into plural form TargetFrameworks and add the framework monikers you wish to support:
1 2 3 4 5 6 7 8 9 10 11 | < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFrameworks >netcoreapp1.1;netstandard1.6;net45;net40</ TargetFrameworks > </ PropertyGroup > < ItemGroup > < Folder Include = "Properties\" /> < Compile Remove = "Properties\AssemblyInfo.cs" /> </ ItemGroup > </ Project > |
The full list of target frameworks (AKA framework moniker) can be found at: https://docs.microsoft.com/en-us/nuget/schema/target-frameworks#supported-frameworks
Of course, not everything is supported in every framework, so we need to add some conditions inside our code and inside our *.csproj file
MSBuild conditions to the rescue
Suppose our library has a dependency on RestSharp Nuget package.
At the time of this writing, the RestSharp package for .NET Core is called RestSharp.NetCore while the package for the full .NET Framework is called RestSharp .
So in order to had the dependency into our *.csproj file we need to separate the reference into two sections. Fortunately, now that MSBuild support the <PackageReference> tag this job becomes so much easier
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFrameworks >netcoreapp1.1;netstandard1.6;net45;net40</ TargetFrameworks > </ PropertyGroup > < ItemGroup > < Folder Include = "Properties\" /> < Compile Remove = "Properties\AssemblyInfo.cs" /> </ ItemGroup > < ItemGroup Condition = "'$(TargetFramework)' == 'netcoreapp1.1' or '$(TargetFramework)' == 'netstandard1.6' " > < PackageReference Include = "RestSharp.NetCore" Version = "105.2.3" /> </ ItemGroup > < ItemGroup Condition = "'$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net40' " > < PackageReference Include = "RestSharp" Version = "105.2.3" /> </ ItemGroup > </ Project > |
Auto Nuget packaging
One of the greatest pains that was with the old version of Nuget and MSBuild was the separation of the Nuget packaging from the project build. Basically, you had to create a *.nuspec file, add all the frameworks configuration into it and then add all the build artifacts into each of the sub-framework configuration. This was tedious.
Now, VS2017 integrates Nuget into the project itself
 with VS2017 and Nuget _ IBlogger - Tamir Dresher_files/nuspecprops.gif)
Embedded nuspec inside your *.csproj (Image taken from http://blog.nuget.org/20170316/NuGet-now-fully-integrated-into-MSBuild.html)
After I filled the fields and checked the ‘Generate Nuget Package on build’, this how my *.csproj look
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFrameworks >netcoreapp1.1;netstandard1.6;net45;net40</ TargetFrameworks > < GeneratePackageOnBuild >True</ GeneratePackageOnBuild > < Company >TamirDresher</ Company > < Authors >TamirDresher</ Authors > < Description >A very impressive package</ Description > < Version >1.2.3</ Version > </ PropertyGroup > < ItemGroup > < Folder Include = "Properties\" /> < Compile Remove = "Properties\AssemblyInfo.cs" /> </ ItemGroup > < ItemGroup Condition = "'$(TargetFramework)' == 'netcoreapp1.1' or '$(TargetFramework)' == 'netstandard1.6' " > < PackageReference Include = "RestSharp.NetCore" Version = "105.2.3" /> </ ItemGroup > < ItemGroup Condition = "'$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net40' " > < PackageReference Include = "RestSharp" Version = "105.2.3" /> </ ItemGroup > </ Project > |
Now, when I build my project or click on ‘Package’ from the project context menu, a Nuget package will be created for all the supported frameworks
You can read about other configuration you can now make to your *.csproj here: https://docs.microsoft.com/en-us/dotnet/articles/core/tools/csproj