Targeting .NET Core

Problem

Since DNX was announced, library authors have been inundated with requests to support .NET Core and the CoreCLR. Up until now, the only real option was to use the DNX-based project.json build system with the Visual Studio xproj projects. Adding these project types into an existing project that already supports a wide-range of platform targets can be challenging. There are a few issues with the current approach:
– Not all project types can be built with project.json
– It’s been a moving target as DNX is rightfully still in beta.
– Without proper guidance, authors have been targeting dnxcore50 in their packages intended for .NET Core instead of dotnet
– To be fair, dotnet is a recent update that has been little publicized

Starting today though, there’s a better way. Just make sure to install the Windows developer tooling as it includes this new functionality.

Terminology

If we go back to the .NET Core presentation back in November, you may remember this diagram:

In terms of terminology, .NET Core should be your target; CoreCLR is just a runtime. Referring to the diagram, the dnxcore50 Target Framework Moniker refers to the box in the upper-right — it’s the ASPNet 5 app model. It is BCL + DNX specific libraries. Similarly, uap10.0 is the Windows Universal app model, BCL + Windows Runtime.

Many (most?) libraries do not actually need the DNX or WinRT dependencies. All they really need are the BCL libraries. What then is the target there? The answer is dotnet. By using dotnet, you instead specify your dependencies in your nuget package and your package will then run on any supported runtime, including CoreCLR, .NET Native and .NET 4.6 (assuming you’re using the newest BCL packages.)

Existing Libraries

What has been lost in the commotion around DNX, CoreCLR and .NET Core is the fact that “Profile 259″+ Portable Class Libraries, class libraries that target a minimum of .NET 4.5, Windows 8 and Windows Phone 8, can run on CoreCLR as-is. You do not need to create a new project or target newer contract/BCL references. All you need is to put your existing library into \lib\dotnet in your NuGet package in addition to the \lib\portable-* directory it is now and list your dependencies in the package.

The only time you might need a new project is if you have platform-specific code. In that case, the new UWP tools for Windows 10 has a better option: “Modern PCLs”. Once you install the UWP tools, create a new Class Library (Portable) in your solution and make sure only .NET 4.6, Windows Universal 10 and ASP Net 5 is checked. When you do that, you’ll get a modern PCL that uses project.json and pulls in the newest .NET Core packages as references. You can then use linked files, shared projects and your existing techniques to build a class library that targets .NET Core. Then, put that in your \lib\dotnet directory and create the dependencies element for it. No magic needed. Using this technique, I was able to adapt several OSS libraries to support .NET Core in very little time.

NuGet Dependencies – the heart of dotnet

As I described in my previous post, the key to making dotnet work is specifying all of your dependencies. This can be a tedious and error-prone process. I’ve built a tool, NuGet.ReferenceGenerator that automates creation of the dependency element for the majority of cases. The tool works with either existing compatible PCL projects and the new “modern PCL” projects.

Just add the NuSpec.ReferenceGenerator NuGet to your package and build. I won’t go over all of the docs, but you can find those on the project site.

At build time, the tool will read the references your assembly requires, determine the source NuGet package and version, and create the <dependencies> element in the NuSpec.

Call To Action

  • If you maintain a library, review any areas where you are currently targeting dnxcore50 and update your NuGet package to put those bits in dotnet. If you are not using any Microsoft.Dnx references, and the majority of libraries do not, then there’s no reason to target dnxcore50 when dotnet reaches a far broader set of targets.
    • Bonus by using the “Modern PCL” projects and/or reusing your existing PCL, your dependencies will be the stable versions, not pre-release. That means your package can be stable too and not wait until Q1 2016!.
  • If you currently have a library that’s a “System.Runtime”-based PCL, one that’s at least portable-win8+net45+wp8, then simply add a copy of the binary to your NuGet package in the dotnet directory. Adding it to \lib\dotnet and leaving a copy in lib\portable-win8+net45+wp8 allows it to work with .NET Core and the existing NuGet v2 clients.
  • Ensure your NuGet package lists all of its dependencies in a <dependencies targetFramework="dotnet"> element. Use the stable package versions, not the DNX pre-release versions. If you don’t want to create and maintain this by hand, use my ReferenceGenerator.
  • Last, but most importantly, make sure your nuget.exe version is up-to-date by running nuget update -self. Version 2.8.6 or later is required to properly package dotnet.