Appendix A: Getting to grips with .NET Core and .NET Standard

This chapter is aimed at clarifying why .NET Standard was created and why .NET Core was made the way it was, as well as some guidance on how to select a target framework when creating a new application.

Summary

A.1 Exploring the motivations for .NET Core

Xamarin uses the cross-platform Mono implementation of the .NET Framework; an alternative platform to the .NET Framework that you can use to build mobile applications.

There are three layers to each stack

  1. Complier & CLR
  2. Base Class Libraries (BCL)
  3. App-specific libraries like Windows Forms and iOS

The Base Class Libraries (BCL) are the fundamental .NET types like int and string, as well as additional APIs for reading files, the API for performing a Task, and more. These types are similar between platforms, but not all features of one are available on the other.

Some other platforms include:

Each of these APIs varies slightly which made it difficult to switch between them. Developers had to know the minute differences, and sharing code between platforms was difficult.

Also, .NET Framework is an older style of monolithic coding, while the development world is trending towards smaller, cross-platform microservices.

The .NET Core platform includes

.NET Core is just another platform, but the real advantage came with the release of .NET Standard. Which ensures each platform implements a standard set of APIs.

A.2 Sharing code between projects

Before the creation of .NET Core, there was a desire to share code between platforms. This was done using Portable CLass Libraries (PCLs).

A.2.1 Finding a common intersection with Portable Class Libraries

When creating a library, you can specify which platforms you want to support. The project would then only have access to the set of common APIs between the platforms. Each platform added reduces the number of available APIs, since the API must be included in all of the selected platforms.

platform venn diagram

You would then end up with a single project and single package that worked on all the platforms.

See here for Stephen Cleary’s list of profiles you could choose

A final issue is that if you wanted to add an additional target platform, you would need to recompile your PCL. That means you need to wait for the profile author to recompile their profile to support the new platform.

A.2.2 .NET Standard: a common interface for .NET

.NET Standard is the successor to PCL Libraries. It defines a set of APIs that a platform must implement. It doesn’t require any downloads on your part, but instead requires that the platform authors must update their code to match the implementations.

Each new version of .NET Standard includes all features of the previous versions. So v1.2 includes all APIs for v1.1 and v1.0. When developing an app on v1.2, you can reference any library that implements any version of .NET Standard lower than 1.2 as well.

Example: UWP version 10 supports .NET Standard 1.4. Therefore it also supports .NET Standard versions 1.0 - 1.3.

.net backwards compatibility

See here for a list of platforms and their .NET Standard version support.

The author prefers this example by David Fowler from the ASP.NET team to really understand what .NET Standard is in terms of C#. Each interface defines an implementation of .NET Standard, and each new version inherits from the previous version. i.e. NETStandard1_1 : NETStandard1_0. You can then target a particular standard, and any platform that implements that Standard will be able to use all the APIs available to it.

Even if a platform implements a given version of .NET Standard, the method may still throw a PlatformNotSupportedException. See section A.3 for more info.

Mike’s note: what kind of bullcrap is this? Can’t wait to hear the justification for this nonsense.

Somehow, apps targeting .NET Framework 4.6.1 can reference .NET Standard 2.0 libraries despite it only implementing .NET Standard 1.4. This is a special case and only applies to .NET Version 4.6.1 - 4.7.0.

.NET Framework v4.7.1 targets .NET Standard 2.0.

The .NET Core team built .NET Core 2.0 to match all the APIs available in .NET Framework 4.6.1, the most popular version of .NET Framework. They also added these APIs to .NET Standard 2.0, since they wanted Standard 2.0 to match the API of Framework 4.6.1. However, Framework 4.6.1 doesn’t contain implementations for some APIs in Standard 1.5 or 1.6. Therefore Framework cannot support Standard 2.0 directly.

Microsoft decided to allow .NET Framework 4.6.1 to reference .NET Standard 2.0 libraries in order to promote developers to write for .NET Standard 2.0.

.NET Blog Post

Link to the blog post here which further explains .NET Standard and this situation.

implementations

The .NET platform was forked many times. This was beneficial because it allowed for tailoring .NET to work on a specific platform that a single-platform wouldn’t be able to do. It causes issues for developers, however, because there is no unified class library.

The diagram above show the “three main flavors of .NET” that you can target. You need to know all three in order to write code that works on all three. With this system, someone would need to develop new versions of .NET to target new operating systems or device capabilities. .NET Standard helps mitigate this

.net core chart

Developers only need to know one base class library. Libraries targeting .NET Standard will be able to run on all .NET platforms.

To summarize, we need .NET Standard for two reasons:

  1. Driving force for consistency
  2. Foundation for great cross-platform tooling

.NET Standard is also compatible with PCLs. You can see the mapping from .NET Standard version here.

In .NET Standard 2.0, we’ll make it possible for libraries that target .NET Standard to also reference existing .NET Framework binaries through a compatibility shim

They’re starting to lose me here…

In order to allow .NET Framework 4.6.1 to support .NET Standard 2.0, we had to remove all the APIs from .NET Standard that were introduced in .NET Standard 1.5 and 1.6.

After looking at NuGet, only six non-Microsoft packages used APIs on .NET Standard 1.5 or later, and Microsoft has reached out to them to mitigate the effects and replace the calls with implementations from .NET Standard.

At this point I stopped reading the blog post because it was a bit over my head and it’s a Tuesday after a 3 day weekend…

.NET Framework compatibility

.NEt Framework can also be reference by .NET Standard libraries through the use of compatibility shims.

A.2.3 Fudging .NET Standard 2.0 support with the compatibility shim

When .NET Standard was first released, no libraries (NuGet packages) would implement it. Since .NET Standard libraries can only reference other .NET Standard libraries, the packages those packages reference must also be updated.

The compatibility shim was an attempt to speed up this implementation. It allows .NET Standard 2.0 libraries to reference .NET Framework 4.6.1 libraries. This is a special case.

If the library uses a .NET Framework specific API, it will throw a runtime exception. .NET tooling will raise a warning every time you build.

A.3 Choosing a target framework for your libraries and apps

The framework you use will depend on whether you’re going to make an application or a class library.

A.3.1 If you’re building an ASP.NET Core app

You can’t target .NET Standard, since it isn’t a platform, it’s a specification. Instead you need to run on an implementation like .NET Framework or .NET Core. You will then be able to refences libraries that target .NET STandard.

The author recommends targeting .NET Core when possible, or .NET Framework 4.7.1. Only use .NET Framework 4.6.1 as a last resort. You can update which framework you are targeting by editing the <TargetFramework> tag in the .csproj file of your project.

You can also multi-target frameworks, but the author has never found this particularly useful. When doing this, use the TargetFrameworks tag instead.

A.3.2 If you’re building a shared library or NuGet package

The author recommends using .NET Standard in most cases. It lets you reach the largest audience. You should also target the lowest possible version, since it will reach the largest audience. This will require trial-and-error to figure out which version has the minimum APIs you require.

Rules from the author:

If you’re targeting .NET Standard 2.0 and there’s a chance it will be used by a library targeting .NET Framework 4.6.1, then multi-target to .NEt Standard 2.0 and .NET Framework 4.6.1 <TargetFrameworks>netstandard2.0;net461</TargetFrameworks>

A.3.3 Referencing .NET Framework libraries from .NET Standard projects

If you reference a .NEt Framework library from a .NEt Standard Library or .NEt Core 2.0 app, you will receive multiple warnings

You can ignore these errors by adding NoWarn=NU1701 attribute to the package reference in the .csproj file, or right-clicking the Solution Explorer, selecting Properties, and enter NU1701 for NoWarn.

enabling no-warn for a reference using the gui

You can also use the Roslyn API analyzer NuGet package. It will check your code for problems. Microsoft.DotNet.Analyzers.Compatibility. This package will analyze your code and warn you when you make an incompatible call or are using deprecated APIs.

Roslyn analyzer warnings