Microsoft has recently been heavily investing in .NET Core, which you can think of as the next generation of the .NET Framework. There are various benefits to .NET Core, the biggest one being that it is cross-platform; thus compliant code can run on Windows, Linux and Mac (and probably others in future).
In this article, we’re going to take one of my smaller projects – Dandago.Finance – and port it to .NET Core. Dandago.Finance is ideal to demonstrate a first migration because it is very small, consisting of a main project (3 classes) and a unit test project (2 classes) – both class libraries.
Before we start, make sure you are using the latest tools (such as the recently released Visual Studio 2017). .NET Core tools have undergone a lot of radical changes (e.g. project.json is dead) so you don’t want to be learning based on something that’s already obsolete. If you’re using VS2017, make sure you have the .NET Core cross-platform development workload installed.
Migrating the main library
We’re going to start a fresh new class library targeting .NET Core and move our code there. Actually, that statement is not entirely correct: if you open Visual Studio 2017, you’ll see that there are at least 3 different kinds of class library you can create (or more depending on additional tooling you may have installed):
- Class Library (.NET Framework)
- Class Library (.NET Core)
- Class Library (.NET Standard)
This is very confusing and I’ve asked a question about this on Stack Overflow yesterday that attracted some pretty detailed answers. In short, if you want your class libraries to be as portable as possible, you need to target .NET Standard. .NET Standard is a specification detailing APIs that need to be available in compatible frameworks. .NET Core, and certain versions of the full .NET Framework, implement .NET Standard. However, they each also incorporate a lot of other runtime-related stuff, so targeting .NET Core specifically means you can’t use your code under the full .NET Framework.
So let’s create a project of type Class Library (.NET Standard). As always, this will create a solution with the same name as the project.
Next, we’ll delete the automatically created Class1 class, and copy the class files from the old Dandago.Finance library to the new project folder. You’ll notice that Visual Studio automatically notices the new files and includes them in the project, without you needing to explicitly add them:
Migrating the test project
Let’s add a new class library for the unit tests, but this time it needs to be a Class Library (.NET Core). If you get this wrong and choose Class Library (.NET Standard) instead, Visual Studio won’t find your tests and the
dotnet test command will refuse to run it (as per this Stack Overflow question). The reason why .NET Standard won’t work for unit tests is detailed in the corresponding answer: in short, we need to specify a target framework that will be responsible for running the tests; .NET Standard on its own is not enough.
Next, we need to add a reference to the Dandago.Finance project.
Now, we can repeat the procedure we did for the main library, and delete Class1.cs and copy over the test classes.
However, this isn’t going to be as smooth as with the main library. The original test project uses NUnit, and at the time of writing, that isn’t fully supported by .NET Core. Fortunately, however, it’s easy to change to xUnit, which does already boast .NET Core support.
First, we need to install the following packages:
Then, we need to make the following substitutions:
using NUnit.Framework; becomes
[TestFixture] goes away
The solution should now build, and the unit tests should run successfully:
Migrating Dandago.Finance to .NET Core has taught us a few things:
- Visual Studio can automatically detect new files for .NET Core / .NET Standard projects.
- Portable class libraries should target .NET Standard.
- Unit test projects should target .NET Core.
- Use xUnit for .NET Core unit tests.