Targeting multiple frameworks in .NET

In this post we’re going to look at the process of targeting multiple .NET frameworks.

You may have seen this concept when installing nuget packages, viewing the package itself and noting that packages have lib folders which (in some cases) have multiple names such as net35, net40 etc. Hence having assemblies which are compatible with those versions of .NET.

For example, the packages/Castle.Core.4.2.1/lib folder contains

  • net35
  • net40
  • net45
  • netstandard1.3

The names are based upon, what’s called, the TargetFrameworkMoniker (or TFM for short), see Target frameworks in SDK-style projects for both a list of TFM’s as well as a Microsoft post of targeting multiple frameworks.

It looks like we need to be using the new SDK csproj files which we can create using either the dotnet CLI or by creating a .NET core or standard projects (or you can use conversion tools).

Let’s therefore walk through the steps for setting up a Class Library that can target a few different frameworks.

  • Create a .NET standard class library
  • Open the csproj file in Visual Studio or your preferred editor
  • Change the following
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
      </PropertyGroup>
    
    </Project>
    

    to use TargetFrameworks (plural) and add any frameworks you’re targeting delimited by a semi-colon, i.e.

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFrameworks>netstandard2.0;net45</TargetFrameworks>
      </PropertyGroup>
    
    </Project>
    
  • Save and if necessary reload Visual Studio to see the effects of these changes.

If all went well you should see The Dependencies section of your project (within Visual Studio) lists both

  • .NETFramework 4.5
  • .NETStandard 2.0

If you now build your project you’ll get both net45 and netstandard2.0 folders/builds in the bin/Debug and bin/Release folders.

We can now either explicitly add assemblies or packages to our framework specific dependencies and ofcourse, by using preprocessor symbols such as NETSTANDARD2_0 and NETFRAMEWORK or NET45 we can begin to conditionally compiler code for the different target frameworks.

We can add nuget to install package and add references to our multiple targets, but in some circumstances we might need to be more specific about which package is referenced by which target.

In such cases we can add the reference to the application using Visual Studio and then edit the csproj ourselves to add a Condition around the reference, for example

<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
  <PackageReference Include="Microsoft.Net.Http" Version="2.2.29" />
</ItemGroup>

In this example, only the .NET 3.4 target will get the reference added to it.

Now we’ve seen how to add conditions to our csproj we can also define constants for use also (or ofcourse using the project properties tab within Visual Studio to add these), for example

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
   <DefineConstants>SOME_CONSTANT</DefineConstants>
</PropertyGroup>

References

Target frameworks in SDK-style projects
Support multiple .NET versions
.NET Standard