10 March 2017
Sharing libraries between .Net Core and .Net Framework applications
f you make any significant commitment to .Net Core there is a fair chance that you’ll need to share some libraries with .Net framework applications. After all, .Net Core is an emerging ecosystem that still has a lot of missing pieces.
In a mixed ecosystem you have two options for sharing libraries. Firstly, you can develop a .Net Standard library that can, in theory, be shared directly between applications so long as the versions match up. Alternatively, you can use multi-targeting to cross-compile a library for more than one platform.
Sharing through the .Net Standard
Microsoft introduced the .Net Standard to provide a common standard for APIs across the Microsoft ecosystem. It can be seen as a successor to portable class libraries (PCLs) that simplifies the business of targeting different platforms. Where PCLs are based on profiles defined by intersecting platform capabilities, the .Net Standard provides a curated set of APIs.
The upshot is that you can create libraries that can be directly referenced by both .Net Framework and .Net Core applications. You just need to ensure that the .Net Standard Library NuGet package is added to any .Net Framework application that wants to reference a .Net Standard library.
Given that there have been more than half a dozen versions of the .Net Standard already it’s not always immediately clear which version to target. In general, the higher the version of .Net standard then the wider range of APIs that will be available to you. The lower the version the wider range of platforms you’ll be able to support.
The catch is that.Net Framework version support for .Net Standard is pretty limited. Each version of the .Net Standard is supported by a different version of the .Net Framework. For example, if you want a library to be available to both .Net Core and.Net Framework 4.5.2 applications then you’ll need to target .Net Standard 1.2.
As ever with .Net Core, you are the prisoner of your dependencies. Although there is increasing adoption of .Net Standard among commonly-used libraries, the support for anything below version 1.3 is pretty sketchy. In practical terms, this can tie you into a minimum .Net Framework version of 4.6.
Most development shops have a mixture of .Net framework versions in production. This can make the adoption of .Net Standard libraries quite difficult, particularly in larger ecosystems. You’d be surprised how much .Net 4.0 or even 3.5 is lurking in some dark corners. Even version 4.5.2 may still be supported by Microsoft, but it is limited to version 1.2 of the .Net Standard.
For messier ecosystems that cannot guarantee a more recent vintage of the .Net framework, multi-targeting can help to widen the reach of shared libraries. This allows you to compile a single project natively for both .Net Standard and your preferred version of the .Net Framework, though it does come at a cost of having to manage multiple sets of compiled output.
This has become a lot more straightforward since Visual Studio 2017 was released. Multi-targeting was a pretty choppy experience in Visual Studio 2015 using the old JSON-based xproj format. You could get a project to compile for more than one framework, but you were not able to use a direct project reference in a .Net Framework project. This required some pretty difficult workarounds: you either had to migrate the target project to the xproj structure or distribute the dependency using NuGet. Neither approach was ideal.
This has been addressed in the new tooling, though you do still have to manually edit the project files to get it working. Re-loading the solution is also recommended after making any manual changes to the frameworks.
The example below shows how you would adjust the TargetFramework element to get a project to compile for more than one framework:
<PropertyGroup> <TargetFrameworks>net452;netstandard1.3</TargetFrameworks> </PropertyGroup>
When you compile this project you will see two outputs in the BIN folder, one for each of the frameworks specified. This allows you to create project references to the shared assembly, both for projects built with .Net Framework 4.5.2 or anything built on .Net Core 1.0.
Migrating existing libraries
When planning shared libraries bear in mind that the .Net Standard is based on a subset of the overall APIs currently available in the .Net Framework. Many of the APIs that you may have grown accustomed to using in the .Net Framework will not be part of the .Net Standard, particularly once you get into those areas that have been most heavily refactored by .Net Core (e.g. ASP.Net).
Implementing existing .Net Framework libraries as shared .Net Standard libraries inevitably requires a migration, similar to porting to .Net Core. Microsoft’s API Port tool can tell you how much work this will involve. It is a command line tool that gives you a detailed breakdown of the types and members that will cause compatibility issues. In some cases, they will require a particular version of the .Net Standard, while others will not be supported at all.
Once again, the greatest difficulties are likely to be around external 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 one of the main intentions of the .Net Standard is to eliminate the need for this kind of workaround.
The whole issue of sharing code should be made easier by the next version of .Net Standard, which is promising a compatibility shim for .between .Net Core and .Net Framework assemblies. This should make it easier to make a commitment to .Net Core as legacy .Net Framework libraries will be accessible to .Net Core code. It remains to be seen how comprehensive this will be or whether it will encompass legacy versions of .Net Framework.