Understanding .NET Standard
In the .NET ecosystem, there are many runtimes. We have the .NET Framework, which is a full machine-wide framework installed on the Windows operating system and provides app models for Windows Presentation Foundation (WPF), Windows Forms, and ASP.NET. Then, we have .NET Core, which is targeted at cross-platform operating systems and devices and provides ASP.NET Core, Universal Windows Platform (UWP), and a Mono runtime that is targeted at Xamarin applications and developers who can use Mono runtime to develop applications on Xamarin and run on iOS, Android, and Windows OS.
The following diagram depicts how the .NET Standard Library provides an abstraction of .NET Framework, .NET Core, and Xamarin with the common building blocks:
All of these runtimes implement an interface known as .NET Standard, where .NET Standard is the specification of .NET APIs that have the implementation for each runtime. This makes your code portable across different platforms. This means the code created for one runtime can also be executed by another runtime. .NET Standard is the next generation of Portable Class Libraries (PCL) we used earlier. Just to recap, PCL is a class library that targets one or more frameworks of .NET. When creating a PCL, we can select the target frameworks where this library needs to be used, and it minimizes the assemblies and uses only those that are common to all frameworks.
The .NET Standard is not an API or executable that can be downloaded or installed. It is a specification that defines the API that each platform implements. Each runtime version implements a specific .NET Standard version. The following table shows the versions of .NET Standard each platform implements:
We can see that .NET Core 2.0 implements .NET Standard 2.0 and that .NET Framework 4.5 implements .NET Standard 1.1., so for example, if we have a class library developed on .NET Framework 4.5, this can easily be added into the .NET Core project because it implements a greater version of .NET Standard. On the other hand, if we wanted to reference the .NET Core assembly into .NET Framework 4.5, we can do so by changing the .NET Standard version to 1.1 without recompiling and building our project.
As we learned, the basic idea of .NET Standard is to share code between different runtimes, but how it differs from PCL is shown as follows:
Portable Class Library (PCL) | .NET Standard |
Represents the Microsoft platform and targets a limited set of platforms | Agnostic to platform |
APIs are defined by the platforms you target | Curated set of APIs |
They are not linearly versioned | Linearly versioned |
.NET Standard is also mapped to PCL, so if you have an existing PCL library that you wanted to convert to .NET Standard, you can reference the following table:
PCL Profile | .NET Standard | PCL Plaforms |
7 | 1.1 | .NET Framework 4.5, Windows 8 |
31 | 1.0 | Windows 8.1, Windows Phone Silverlight 8.1 |
32 | 1.2 | Windows 8.1, Windows Phone 8.1 |
44 | 1.2 | .NET Framework 4.5.1, Windows 8.1 |
49 | 1.0 | .NET Framework 4.5, Windows Phone Silverlight 8 |
78 | 1.0 | .NET Framework 4.5, Windows 8, Windows Phone Silverlight 8 |
84 | 1.0 | Windows Phone 8.1, Windows Phone Silverlight 8.1 |
111 | 1.1 | .NET Framework 4.5, Windows 8, Windows Phone 8.1 |
151 | 1.2 | .NET Framework 4.5.1, Windows 8.1, Windows Phone 8.1 |
157 | 1.0 | Windows 8.1, Windows Phone 8.1, Windows Phone Silverlight 8.1 |
259 | 1.0 | .NET Framework 4.5, Windows 8, Windows Phone 8.1, Windows Phone Silverlight 8 |
Considering the preceding table, if we have a PCL that targets .NET Framework 4.5.1, Windows 8.1, and Windows Phone 8.1 with the PCL profile set to 151, it can be converted to the .NET Standard library with version 1.2.
Versioning of .NET Standard
Unlike PCL, each version of .NET Standard is linearly versioned and contains the APIs for the previous versions and so on. Once the version is shipped, it is frozen and cannot be changed, and the application can easily target that version.
The following diagram is a representation of how .NET Standard is versioned. The higher the version is, the more APIs will be available, whereas the lower the version is, the more platforms will be available:
New improvements in .NET Standard 2.0
.NET Core 2.0 is targeted at .NET Standard 2.0 and provides two major benefits. This includes the increase in the number of APIs provided from the previous version and its compatibility mode, as we will discuss further in this chapter.
More APIs in .NET Standard 2.0
More APIs have been added into .NET Standard 2.0 and the number is almost double that of the previous .NET Standard, 1.0. Additionally APIs like DataSet, collections, binary serialization, XML schema, and others are now part of .NET Standard 2.0 specification. This has increased the portability of code from .NET Framework to .NET Core.
The following diagram depicts the categorical view of APIs added in each area:
Compatibility mode
Although more than 33K APIs have been added into .NET Standard 2.0, many of the NuGet packages still target .NET Framework, and moving them to .NET Standard is not possible, since their dependencies are still not targeted at .NET Standard. However, with .NET Standard 2.0, we can still add packages which show a warning but don't block adding those packages into our .NET Standard library.
Under the hood, .NET Standard 2.0 uses compatibility shim, which solves the third party library compatibility issue and makes it easy in referencing those libraries. In the CLR world, the identity of the assembly is part of the type identity. This means that when we say System.Object
in .NET Framework, we are referencing [mscorlib]System.Object
and with .NET Standard, we are referencing [netstandard]System.Object
, so if we are referencing any assembly which is part of .NET Framework, it cannot be easily run on .NET Standard and so compatibility issues arise. To solve this problem, they have used type forwarding which provides a fake mscorlib
assembly that type forwards all the types to the .NET Standard implementation.
Here is a representation of how the .NET Framework libraries can run in any of the .NET Standard implementations using the type forwarding approach:
On the other hand, if we have a .NET Framework library and we wanted to reference a .NET Standard library, it will add the netstandard
fake assembly and perform type forwarding of all the types by using the .NET Framework implementation:
Note
To suppress warnings, we can add NU1701 for particular NuGet packages whose dependencies are not targeting .NET Standard.