21 November 2016

Sharing libraries between .Net Core and .Net Framework applications

There are several options for sharing projects between .Net Core and .Net Framework applications. As ever with Core development, you tend to be constrained by your dependencies and the frameworks they support.

Compiling projects for multiple frameworks

Although you cannot directly combine complied .Net Core and .Net framework assemblies you can potentially use multi-targeting to explicitly compile a Core project for more than one framework. However, the tooling for is a immature and the experience tends to be pretty rocky. This situation is likely to persist now that we are transitioning away from project.json files back to to csproj and MSBuild in Visual Studio 2017.

Multi-targeting in the out-going project.json structure is achieved by adding multiple entries to the “frameworks” sectuib. The example below shows a simple configuration file for a class library that will compile for both .Net 4.6.2 and .Net Standard 1.6 (i.e. .Net Core):

{
  "version""1.0.0-*",
 
  "dependencies": {
    "NETStandard.Library""1.6.0"
  },
 
  "frameworks": {
    "net462": {},
    "netstandard1.6": {}
  }
}

For the new .csproj files you need to add a “TargetFrameworks” section as shown below:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFrameworks>netcoreapp1.0;net462</TargetFrameworks>
    </PropertyGroup>
</Project>

Both these approaches have the same effect. When you compile the project you’ll see two separate versions of the output in the BIN folder, one for each of the frameworks that you have specified.

As with any Core-related development, you will be at the mercy of your project dependencies. Multi-targeting will only work if all the dependencies in the project also support your target frameworks. Some implementation differences can be smoothed over with conditional compilation statements, but if one of your dependencies is not available at all to a framework version then you will need to consider an alternative.

Referencing a multi-targeted project in Visual Studio

The catch with multi-targeting is that you can’t reference these libraries directly in a .Net Framework project due to a limitation of the Visual Studio tooling. In Visual Studio 2015 you can create a direct reference in Visual Studio using the “Add Reference” dialog but this won’t let you directly access any members or even see them in the object browser. In Visual Studio 2017 you can’t even be able to create the reference.

One workaround for this is to ship your cross-framework library as a NuGet package. This can be done easily using the “pack” command as shown below:

dotnet pack -o c:\temp\packages

This will automatically package up both versions of the assembly into a NuGet package along with the debug symbols so they can be pulled directly into both types of project. It works, but it creates an awkward development workflow where you pack and update a library every time you make a change. This is not really viable for assemblies being worked on within the same development project.

For project.json based projects you also had the option of building .Net Framework applications as an .xproj-based Core project. The configuration below shows what a basic project.json file looks like for a console app that runs using v4.6.2 of the .Net framework:

{
  "version""1.0.0-*",
  "buildOptions": {
    "emitEntryPoint"true
  },
 
  "dependencies": {
    "SharedCoreLibrary""1.0.0-*"
  },
 
  "frameworks": {
    "net462": {}
  }
}

This stripped-down file only has one entry in the “frameworks” section and the project will compile and run on top of the .Net framework. You can reference multi-targeted libraries through this project as well as adding in any other .Net framework dependencies and packages that you want to use. One hopes that a similar level of cross-platform operation will soon be available for projects developed using the new .csproj syntax.

Using portable class libraries

Given how messy multi-targeting is then a more viable option may be to compile and share assemblies as a portable class library (PCL). With a bit of fiddling this can be used to create a single artefact that can be referenced directly from both a .Net framework and .Net Core project.

When you first create a portable class library, the template offers to target the library for .Net 4.6 and .Net Core 1.0 as shown below:

portable-class-library-create

This will work fine with a .Net Framework project and the.Net Core project will even let you add the reference and compile. The catch is that the Core project will issue build warnings and you won’t get any Intellisense in Visual Studio.

The only way to get a PCL working smoothly against both types of project is to switch the portable class library to compile against a version of .Net Standard:

  • In the solution explorer, right-click on the project name and select “Properties”
  • In the “Targeting” section of the “Library” page there will be a link saying “Target .Net Standard Profile”.

portable-class-library-convert

Clicking on this will reload the project with references re-jigged to compile against .Net standard as opposed to the default PCL profile. You should now be able to reference the library from .Net framework and .Net Core projects smoothly, complete with Intellisense and hassle-free compilation.

Once again, whether this approach is going to work for you depends on the framework versions required by your project dependencies. Given the limited support for .Net standard across NuGet it may be difficult to build anything beyond basic data classes as PCLs that can be fully shared between .Net Core and the .Net framework.

Filed under ASP.NET, C#, Net Framework.