close icon
.NET

.NET Core vs .NET Framework vs .NET Standard: A Guided Tour

A guide for understanding the differences between .NET, .NET Core, .NET Framework, .NET Standard, etc. by exploring the history of the platform.

Last Updated On: October 15, 2021

If you are confused in front of the different facets of .NET, or if you are not clear on the differences between .NET, .NET Core, .NET Framework, .NET Standard, and similar, well, this article is for you.

What .NET Means Today

Say you are a new developer that wants to approach .NET. Caught up in the excitement, you navigate to Microsoft's website and find the following definition:

.NET: Free. Cross-platform. Open source. A developer platform for building all your apps (web, mobile, desktop, game, IoT).

Cool! This platform looks great! You can build any kind of application by using C# or any other .NET compatible programming language.

However, there are issues are around the corner...

Maybe you find an awesome library on NuGet, but learn that it is for the .NET Framework and cannot use it in your project unless you target your project to .NET Standard 2.0. In that case, your application will also run on .NET Core.

What? Isn't .NET Framework just .NET? And what are .NET Standard and .NET Core?

Welcome to the .NET maze! If you don't want to get lost in it, you need Ariadne's thread.

I understand that not everyone likes history, especially in the IT field. Many people prefer to know what and how to do things today. But, as it happens in everyday life, the past has a great influence on the present and also on the future. To understand today's and future .NET, you need to take a step back and trace its history, at least in broad strokes.

In the Beginning Was the .NET Framework

In 2002, Microsoft promised one framework to build applications with any programming language: C# (born for that occasion), Visual Basic, and many other languages. The framework granted a common API set, language independence, interoperability with the underlying operating system and other non-.NET applications, portability (at least in perspective, at the time), and many interesting features.

Although the long-term idea was to make .NET a cross-platform framework, the .NET Framework only ran on Windows.

Don't get me wrong. Even if I'm speaking in the past tense, the .NET Framework is still alive and operative. Its current version is 4.8, and it is the last version of the framework, as you will learn later. But a huge amount of code runs on it, so you cannot consider it a dead framework yet.

Mono on the Stage

One interesting thing is that Microsoft published the specifications of the Common Language Infrastructure (CLI), that is, the .NET Framework runtime, and the C# language. Even better, they set them as open standards: ECMA-335 and ECMA-334. So pretty much anyone could implement the .NET runtime and the C# programming language.

In 2007, this paved the way for a project to port .NET to Linux: the Mono Project. Other attempts to port .NET on Linux were made: DotGNU and CrossNet, among others. However, only the Mono Project attracted significant interest and generated a production-ready framework.

However, not everything in the .NET Framework could be ported to Mono due to some strict dependencies on Windows. In addition, the state of Mono development was usually not so aligned with the current state of the .NET Framework. This actually created some friction with the real portability of .NET applications to Linux.

.NET Everywhere

The open specifications of the .NET fundamental components were the first step towards the quick spread of the framework. Microsoft on one side and other independent developers on the other side brought the .NET Framework to different platforms.

When the .NET Framework was born, Microsoft also released the .NET Compact Framework. It was a reduced version of the framework designed to run on devices with limited computing capacity, such as PDAs, mobile phones, set-top boxes, etc. In 2007, the .NET Micro Framework was launched: a more efficient version of the .NET Compact Framework that could also run directly on the hardware.

The same year, Silverlight brought .NET to the browser, providing developers with a framework for building rich Internet applications similar to Adobe Flash.

In 2009, the MonoTouch project started. It was the first attempt to port the Mono framework (that is, the Linux implementation of the .NET Framework) to iOS and Android. In a few years, the MonoTouch project became the foundation for Xamarin, the framework for building Android and iOS apps with C# (2013).

So, as early as 2013, .NET allowed you to build applications for Windows and Linux machines, for embedded devices, for the browser, and for iOS and Android devices.

You may think that it was amazing! However, the proliferation of different environments led to a fragmentation of the framework itself. That wasn't much of a problem for those who were developing applications. Applications are usually platform-specific. This fragmentation was a big problem for library developers. In fact, a .NET assembly could theoretically be loaded in any .NET runtime. Unfortunately, it could break at any point if it calls an API that wasn’t supported by the platform it is running on.

The cross-platform dream had not yet come true.

"As early as 2013, .NET allowed you to build applications for Windows and Linux machines, for embedded devices, for the browser, and for iOS and Android devices."

Tweet

Tweet This

The Rise of .NET Core

In 2014, to pursue the goal of an actual cross-platform development framework, Microsoft started writing .NET Core from scratch. The first release was ready in 2016. The new framework was a complete redesign of the .NET specifications with cross-platform support in mind. In fact, its runtime ran on Windows, Linux, and macOS.

This new framework didn't have the backward-compatibility constraints that the .NET Framework had. Its modular architecture provided smaller versions of the framework's core components, letting the developer download the additional components from the NuGet repository. This refactoring enabled simplified deployment and portability.

The Need for a Standard

While .NET Core was a step in the right direction for cross-platform support, it brought yet another implementation in the already entangled .NET ecosystem. In other words, a library developer has another potential pain point for the portability of their library.

Microsoft tried to put order into this chaos by introducing the .NET Standard. This is not just another framework implementation, but a formal specification of .NET APIs that multiple .NET platforms have to implement. Different .NET Standard versions define different .NET API sets. This way, a .NET implementation declares which .NET Standard version it supports. The library developer needs to target that specific .NET Standard version.

For example, if you want your library to run on .NET Framework 4.5, .NET Core 2.1, and Mono 4.6, you should target your project to .NET Standard 1.1. See the official documentation to take a closer look at the .NET Standard.

Targeting a .NET Standard is a matter of specify the Target Framework Moniker (TFM) in the .NET project file. It is something like the following in your .NET project file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0</TargetFrameworks>
  </PropertyGroup>
  ...
</Project>

Only .NET from Now On

Finally, in November 2020, .NET 5 was released. This new version of the framework aims to be the unified .NET platform from now on. No more need for different implementations: .NET 5 is the common set of APIs that runs on Windows, Linux, Mac, iOS, and Android. So, if your project targets .NET 5, your code will run on all those platforms.

.NET 5 platform

[Source: Microsoft]

If you need a given platform's APIs, you should use a specific TFM. For example, if you want to use Windows.Forms for your desktop application, you need to specify the net5.0-windows TFM, since this feature is supported on the Windows operating system. Of course, in this case, you know that your code will run only on that specific platform.

.NET 5 removes the need for .NET Standard. Actually, you may think of .NET 5 as the evolution of .NET Standard. However, .NET 5 is not a formal specification but an actual implementation. Also, the release of .NET 5 marks the end of .NET Framework.

At this point, you might ask: .NET 5 is the subsequent version of .NET Core 3.1. What happened to .NET 4?

The answer is pretty simple: there is no .NET 4! Microsoft decided to skip this version to avoid confusion with .NET Framework 4.x. So, from now on, .NET will have no more Framework, Core, Compact, or Micro. The future of .NET will have no other qualifier than just its version.

Aside: Securing ASP.NET Core with Auth0

Securing ASP.NET Core applications with Auth0 is easy and brings a lot of great features to the table. With Auth0, you only have to write a few lines of code to get a solid identity management solution, single sign-on, support for social identity providers (like Facebook, GitHub, Twitter, etc.), and support for enterprise identity providers (like Active Directory, LDAP, SAML, custom, etc.).

On ASP.NET Core, you need to create an API in your Auth0 Management Dashboard and change a few things on your code. To create an API, you need to sign up for a free Auth0 account. After that, you need to go to the API section of the dashboard and click on "Create API". On the dialog shown, you can set the Name of your API as "Books", the Identifier as "http://books.mycompany.com", and leave the Signing Algorithm as "RS256".

Creating API on Auth0

After that, you have to add the call to services.AddAuthentication() in the ConfigureServices() method of the Startup class as follows:

string authority = $"https://{Configuration["Auth0:Domain"]}/";
string audience = Configuration["Auth0:Audience"];

services.AddAuthentication(options =>
{
  options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
  options.Authority = authority;
  options.Audience = audience;
});

In the body of the Configure() method of the Startup class, you also need to add an invocation to app.UseAuthentication() and app.UseAuthorization() as shown below:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

Make sure you invoke these methods in the order shown above. It is essential so that everything works properly.

Finally, add the following element to the appsettings.json configuration file:

{
  "Logging": {
    // ...
  },
  "Auth0": {
    "Domain": "YOUR_DOMAIN",
    "Audience": "YOUR_AUDIENCE"
  }
}

Note: Replace the placeholders YOUR_DOMAIN and YOUR_AUDIENCE with the actual values for the domain that you specified when creating your Auth0 account and the Identifier you assigned to your API.

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon