Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Multi-Targeting and Porting a .NET Library to .NET Core 2.0

.NET Standard and .NET Core have been on my mind for a long time now - years really, but the reality is while I've been using the technology quite a bit, I've not jumped in with both feet. In fact, to date I have yet to build anything 'real' for customers beyond a few internal infrastructure projects and quite a few sample applications.

For me personally, .NET Standard 2.0 and .NET Core 2.0 with their much bigger base library foot print and the real possibility of porting the majority of existing library code over to .NET Core really has been a deciding factor for me to start moving some of my existing full framework libraries that I've been using for as long as I have been using .NET to .NET Core 2.0. Being able to bring some of the tools I use to be productive over to .NET Core is actually pretty important factor to overcoming my reluctance to move into .NET Core. Nobody wants to rewrite code they already have just to get back to square one, but with .NET Core 2.0 it really looks like most code will migrate pretty easily.

This isn't just important to me personally, but I think this is a vital requirement for moving much of the support libraries that exist for .NET into .NET Core and providing the full featured eco-system that we've come to expect from .NET applications. Currently with .NET Core 1.x it's been hit or miss feature wise to feel confident you can actually make it through a project without getting stuck with some missing core feature you can't easily find and have to build from scratch. My feeling is that .NET Core 2.0 will change all that by making it possible for most libraries to be ported with minimal effort.

In this post I describe porting an existing full framework library to .NET Core 2.0 and multi-targeting the project to support .NET 4.5, 4.0 and .NET Standard 2.0. The porting process was even easier than I expected, although the tooling required a bit of patience to get on with.

What you need to follow along:

Note that currently there's no support for .NET Core 2.0/.NET Standard 2.0 in the release version of Visual Studio, and that's why the Preview install is required. You can install the minimal .NET and .NET Core payload for a lightish install, and the install is side by side with Visual Studio 2017 RTM so both work.

.NET Standard?

A key concept to the porting process is .NET Standard 2.0 and how it relates to .NET Core 2.0.

For those of you that don't know, .NET Standard is a specification that serves as a blue print for .NET runtime implementations. The standard specifies what base features the runtime has to implement to support it. .NET Standard describes the base API library - what we used to think of as the Base Class Library (BCL) in full framework that make up the core features of the platform.

.NET Standard is a standard not an implementation and it's up to the runtime to implement the features set forth in the standard. The logistics of this involve some runtime magic where each runtime provides a set of .NET Standard forwarding assemblies that map the .NET Standard APIs to the actual underlying APIs on the specific runtime.

For the purposes of this discussion, the salient point is that .NET Core 2.0 is an implementation of .NET Standard 2.0 which means that if I implement a .NET Standard 2.0 compliant DLL it will run on .NET Core 2.0. And any other platform like .NET 4.6.1, Xamarin, Mono, UWP and Unity all of which will eventually support .NET Standard 2.0. By targeting .NET Standard 2.0 I can insure that my DLL will run on any of the target platforms that .NET Standard supports.

The big win with .NET Standard is that it provides a common interface to consumers of a library, as well as an official guideline to the actual runtime implementers.

For Visual Studio purposes targeting .NET Standard for a class library is also what gives the new SDK project type that is required to make multi-targeting work.

I don't want to rehash all the details about how .NET Standard works here, but you can read my earlier blog post .NET Standard 2.0 - Making Sense of .NET Again for a more detailed discussion on just how that works.

The key takeaway for this post is that your .NET Applications can now target .NET Standard 2.0 in your class libraries (or applications) and can have a very reasonable expectation of interoperability for a number of platforms. In this post I'll talk about full framework .NET 4.5, 4.0 and .NET Core 2.

Putting it to a Test: Porting a .NET 4.5/4.0 Library

To really put this all into perspective I decided to move one of my libraries - Westwind.Utilities - to .NET Core 2.0 and in the process target .NET Standard 2.0, .NET 4.5 and .NET 4.0 all in a single project. Multi-targeting from a single project is an awesome feature that makes it possible to create a single .NET library project that can target multiple .NET Framework targets. Using a single project I can create binaries - and a NuGet package if desired - for multiple platforms.

Westwind.Utilities is a really old project that I've been using since the very early years of .NET and it's interesting in this context because it contains a large hodge-podge of functionality that touches a lot of different framework features in a single library. If I built this today I would probably have broken most of the features out into separate projects, but there's a lot of convenience in having these features I use in almost every project provided in a single package. Anyway, the point is this is very typical full framework legacy .NET code that was designed with no concept of .NET Core and makes a for a good example of what you're likely to find when you start porting full framework code to .NET Core 2 and later.

Creating a new .NET Standard Project

The first step for moving this library is to create a new .NET Standard Class Library:

Creating a .NET Standard Class library

This creates a new SDK style project using a csproj file. This is the new, more streamlined, MSBUILD based project format that uses the underlying dotnet command line tooling to build, test and publish your library. These projects can also target multiple runtime versions, and when compiled, output multiple versions of your assembly for each runtime. You can also optionally publish and create a Nuget package that includes all runtime versions. The new SDK format lets you configure NuGet attributes directly in the csproj file configuration.

I also set up a test project at the same time to move over the existing tests for the old project.

Multi-Target Projects in Visual Studio

When it is all said and done, here's the what the final ported project ends up looking like in Visual Studio:

A multi-targeted .NET project in Visual Studio

Notice the three targets for .NET 4.5, 4.0 and .NET Standard 2.0 all living in the same project. You can also see the dependencies that each of the different runtime implementations are pulling in. .NET Core only shows the two packages (Json.net and SqlClient) I pulled in, while .NET 4.5 shows the specific assembly reference - both explicit assemblies and dependent assemblies (the ones with the lock in Solution Explorer).

The good news is that you can now have a single project with multiple targets with one single build step. Yay!

The bad news is that there's currently no visual tooling support for managing multi-target projects in Visual Studio and you have to deal with the .csproj file directly to change targets or apply special target configuration settings.

To ram that point home, when I go to the project properties for the my class library project here's what I see:

TargetFramework is missing in Visual Studio

Yup - no runtime target shows because the UI can't handle multiple frameworks (it only looks at <TargetFramework> not <TargetFrameworks>). In order to manage multiple frameworks you currently have to work directly with the .csproj file.

Luckily that is now a lot easier for a couple of reasons:

  • Implicit File Inclusion
    The new .csproj format no longer explicitly needs to add every file to the project. Code files are now implicitly considered part of the project and so no longer need to be explicitly included in the project which drastically reduces the size and complexity of the project file as well as reducing the change churn in the file which is better for source control management. There are still overrides that let you specify custom behaviors for specific files or add files that need to be explicitly included or pushed out as content into the build folder. But for your base code files, they are considered included by default unless you tell the project otherwise.

  • Side by Side Editing
    You can now easily edit the .csproj file from Visual Studio while the project is still active. Most changes are immediately reflected in Visual Studio although in the current preview that behavior is still a little spotty and some things require an explicit project/solution reload.

You can now edit CsProj files while the project is open

Posted in .NET  .NET Core  ASP.NET Core  

The Voices of Reason


June 23, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

Hey Rick, great article.

I noticed you're using ConfigurationManager there. There is currently a preview build out for System.Configuration.Configuration manager for NetStandard 2.0. Have you tried to use it at all?

I'm getting an error complaining that ConfigurationManager is found within multiple namespaces after adding it, despite having removed all references to the System.Configuration assembly.

Anyway wasnt sure if you had any ideas about that.

Thanks for the good write up!

Rick Strahl
June 23, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Will - I haven't used it but I suspect you need to ensure that the package is added only to the .NET Standard target not the full framework ones since those have it as part of the System.Configuration reference.

Stefan Matsson
June 25, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

What a coincidence, I have been thinking about writing a similar post for some time now. Great post! 😃 I just wanted to point out that in VS 2017 you can actually change the target framework from Visual Studio in the dropdown just below the tabs with open files.

Screenshot: https://drive.google.com/file/d/0B6H3S-PTnF26NmJfY1JId2p1ZUU/view?usp=sharing (where it says "tusdotnet(netstandard1.3)")

Rick Strahl
June 25, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Stefan - you can change the target framework, but only if you have a single target. If you target multiple frameworks it doesn't show anything (because the UI wouldn't work for that).

Stefan Matsson
June 26, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Rick I'm not sure I get the difference. My code targets .NET Framework 4.5.2 and .NET Standard 1.3 ("net452;netstandard1.3") and I get to chose between net452 and netstandard1.3 in the dropdown. When I compile it compiles for both .NET 4.5.2 and .NET Standard 1.3. Care to explain how it differs from your code? 😃

Rick Strahl
June 26, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Stefan - I'm using the .NET Core 2.0 SDK Preview tooling and VS 2017.3 Preview 1. Perhaps you're using current release of VS 2017 and perhaps with a project.json rather than the SDK tooling? I'm not sure all I can see is that it's not working and when asked that came back as a known issue at the moment.

Stefan Matsson
June 27, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

2017.2 and the older SDK here so maybe it hasn't been added to 2017.3 yet. "The bad news is that there's currently no visual tooling support for managing multi-target projects in Visual Studio and you have to deal with the .csproj file directly to change targets or apply special target configuration settings." is a bit confusing though as it does work in older versions and is probably just a bug in the current version. Just wanted to point that out.

Kori Francis
June 27, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

Finally, finally, finally. I've been wanting to port my libraries for a while and this is the first article that really helped me get there. THANK YOU! (see my thread with @visualstudio https://twitter.com/djbyter/status/867429782333652993)

Rick Strahl
June 27, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Stefan - Maybe it's just for .NET Standard 2.0 projects since that's a new SDK. I didn't check for .NET Standard 1.3 and earlier which are 'released' SDKs.

June 28, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

Thanks you for this information Rick. I was looking over the Cake project and this really cleared things up for me with regarding to multi-framework solutions.

August 14, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Rick - You and Stefan are talking of different things (look at his screenshot): he is talking about the dropdown box inside the editor while you are talking about the target framework dropdown box on the project property page.

Rick Strahl
August 14, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Felix - that dropdown only controls what you see in the editor, not what the project is actually using for compilation. It's useful as you can edit code and see the appropriate Intellisense and error information in the editor, but it won't affect the build process for example when running tests.

For example, try changing the dropdown and then run a test that steps into code - if the platform specified in the .csproj file differs it'll always use what's in the .csproj file.

August 21, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

Painted myself into a corner and have just found your article.

Implementing legacy W/S with the associated DTO's & POCO's that NEED to come with the W/S.

What a nightmare .core debacle.

Finally somebody actually saying the elephant in the room that as you pointed out it was unusable in a real world enterprise scenario.

Cheers 😉

Mark D
September 06, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Rick, have you ported an MVC Core Project to 2.0 on the full framework yet? I can't seem to find the right settings .csproj configuration to get Microsoft.AspNetCore.* libraries to install and still have access to the full framework to use SQL Reporting Services. This was all oworking very nicely using 1.1 on a full framework configuration.

October 23, 2017

# re: Multi-Targeting and Porting a .NET Library to .NET Core 2.0

@Rick, great post (sorry I'm late to the party). I've been in the process of porting several of my libraries to .NET Core and I had been struggling with the idea of doing multi-targeting. In any event, your post was incredibly informative and I was able to breeze through a couple conversions relatively smoothly. Invariably, I've run into the myriad of things that we "depend" on that aren't available under as nuget packages and have made adjustments. Thanks a bunch!


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2017