How to Multi-Target a .Net Core Class Library with Csproj

How do you multi-target a .NET Core class library with csproj?

You need to manually edit the project file and add s to the default TargetFramework and basically change it to TargetFrameworks. Then you mention the Moniker with a ; separator.

Also you can put the Nuget package references in a conditional ItemGroup manually or using VS Nuget Package Manager.

Here is what your .csproj should look like:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.6;net452</TargetFrameworks>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Azure.DocumentDB">
<Version>1.12.0</Version>
</PackageReference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.6'">
<PackageReference Include="Microsoft.Azure.DocumentDB.Core">
<Version>1.1.0</Version>
</PackageReference>
</ItemGroup>
</Project>

Another workaround I do these days because of missing documentation is that I create a project in VS2015 and form the project.json using the available documentation and intellisense, then open the solution in VS2017 and use the built-in upgrade. I will then look at the csproj file to figure out how to make that configuration happen.

Multi-targeting more esoteric targets without a Moniker:

Microsoft:

PCLs are not recommended+

Although PCLs are supported, package authors should support
netstandard instead. The .NET Platform Standard is an evolution of
PCLs and represents binary portability across platforms using a single
moniker that isn't tied to a static like like portable-a+b+c monikers.

If you want to target a Portable Profile it doesn't have a predefined moniker so Portable Profiles also can't infer TargetFrameworkIdentifier, TargetFrameworkVersion, and TargetFrameworkProfile. Also a compiler constant isn't defined automatically. Finally you have to add all assembly references none are provided by default.

This Example below is taken from a project that used the dynamic keyword so it additionally needed the Microsoft.CSharp assembly, thus you can see how it's references for different targets.

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.5;net40;portable40-net45+sl5+win8+wp8</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Profile158</TargetFrameworkProfile>
<DefineConstants>$(DefineConstants);PORTABLE158</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.5'">
<PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows" />
</ItemGroup>
</Project>

Multi-targeting .net core 2.2 with .net 4.6.1

I have yet to understand how multi-targeting in one project works, so what worked for me, was to create the specific (connection to access db) feature in a separate webapi project targeted in .net 4.8. The controller calls the web api method internally via httpClient and does the job.
I know that it is not ideal but for the time constraints that we have, it is a good solution.

Multiple target framework project: different versions of the same NuGet package on different frameworks?

A simple way to do it is to add the <PackageReference ...> nodes conditionally:

<ItemGroup>
<!-- ... -->
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.9" Condition="'$(TargetFramework)' == 'net48'" />
<!-- ... -->
</ItemGroup>

This is a modified example from https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#adding-a-packagereference-condition, which gives more details if required.

How to Multi target a library project with WPF controls

Some WPF items migrated to a new library System.Xaml starting at .NET 4.0

The error The name 'InitializeComponent' does not exist in the current context is being thrown only when the .NET 4.0 target is being built.

To fix this, the following block needs to be added to the csproj file

<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="System.Xaml" />
</ItemGroup>

Also, the xaml pages need to be built as a page, so the following also needs to be added to the csproj file

All xaml files that need to be compiled as page.

<ItemGroup>
...
<Page Include="Path\to\SomeWindow.xaml" />
<Page Include="Path\to\SomeOtherWindow.xaml" />
...
</ItemGroup>

This will remove the xaml files from your solution explorer, so a workaround was found here that adds the following blocks to get xaml pages built but still showing up in the Solution Explorer.

<ItemGroup>
<Page Update="@(Page)" SubType="Designer" Generator="MSBuild:Compile" />
</ItemGroup>

<ItemGroup>
<None Include="@(Page)" />
</ItemGroup>

How do you specify different dependencies and symbols when multi targeting a .NET Standard class library?

The accepted answer from your previous question which you linked to already has the answer: use <ItemGroup>s with Conditions testing for $(TargetFramework). Slightly modified code from that answer:

<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Azure.DocumentDB" Version="1.12.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.6'">
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="1.1.0" />
</ItemGroup>

For preprocessor directives, you don't need to do anything. Directives like NET452 or NETSTANDARD1_6 are defined automatically.

How do I reference a multi-target .NET Core class library from a 4.6.1 project within the same solution?

Yes, this works fine! If your .NET 4.6.1 application is also using project.json/xproj, then it's as simple as:

"dependencies": {
"MySharedLibrary": {
"version": "1.0.0",
"target": "project"
}
}

The target: project value tells NuGet to look in the local solution for the library, instead of in your package sources.

If your .NET 4.6.1 application is a .csproj project, you'll have to wait for the future tooling updates in Visual Studio (this isn't supported yet, but it will be). You can work around this by creating a NuGet package from your library (with dotnet pack) and adding it to your project as a normal package - either by hosting on NuGet/MyGet, or your own local feed.



Related Topics



Leave a reply



Submit