blog post image
Andrew Lock avatar

Andrew Lock

~11 min read

Understanding the .NET ecosystem: The evolution of .NET into .NET 7

I've been working hard on the latest edition of my book, ASP.NET Core in Action, Third Edition, working through the final review process. There's a lot of new content in this edition, so we chose to remove one of the appendices from the book, trying to make sense of the .NET ecosystem. Rather than throw it away, I've turned it into a couple of posts here!

Although this post didn't make it into the book, if you like what you see, take a look at ASP.NET Core in Action—for now you can even get a 35% discount by entering the code au35loc into the discount code box at checkout at manning.com. On top of that, you'll also get ebook copies of the first and second editions, free!

This post covers:

  • The history of .NET, leading to the development of .NET Core
  • The position of .NET 7 in the .NET ecosystem

In the next post I'll cover:

  • Sharing code between projects with .NET Standard
  • The future of .NET Standard with .NET 7

The .NET ecosystem has changed a lot since .NET was first introduced, but the development of .NET Core and .NET 5+ has resulted in a particularly large degree of churn and the introduction of many new concepts.

This churn isn’t surprising given Microsoft’s newfound transparency regarding the development process and building in the open on GitHub. Unfortunately, it can be confusing for developers new to .NET, and even to seasoned veterans! In this post, I’ll try to straighten out some of the terms that developers new to .NET often find confusing, as well as provide some context for the changes.

In this post I’ll discuss the history of the .NET ecosystem, how it has evolved, and the issues Microsoft were attempting to solve. As part of this, I’ll discuss the similarities and differences between .NET 7, .NET Core, and .NET Framework.

.NET Core wasn’t developed in isolation, and one of its primary design goals was to improve the ability to share code between multiple frameworks. In the next post I’ll describe how this was achieved in pre-.NET Core days, using Portable Class Libraries (PCLs) and the successor approach using .NET Standard. Finally, in the next post, I’ll discuss what .NET 7 means for .NET Standard.

Exploring the .NET platforms that prompted .NET Core

If you’re a .NET developer, chances are you’re already familiar with the .NET Framework. The .NET Framework, version 4.8.1 at the time of writing, is a Windows-only development platform that you can use for both desktop and web development. It’s installed by default on Windows and was historically used for most desktop and server .NET development.

If you’re a mobile developer, you might also be familiar with the Xamarin framework, which uses the cross-platform Mono implementation of the .NET Framework. This is an alternative platform to the .NET Framework that you can use to build mobile applications on Windows, Android, and iOS.

Historically, these two platforms were completely separate, but they consisted of many similar components and implemented similar APIs. Each platform contained libraries and app models specific to their platform, but they used similar fundamental libraries and types, as shown in figure 1.

Image showing the layers that make up the .NET Framework.
Figure 1. The layers that make up the .NET Framework. Each layer builds on the capabilities of the layer below, with the highest layer providing the app models that you’ll use to build your applications.

At the bottom of each stack is the tooling that allows you to compile and run .NET applications, such as the compiler and the common language runtime (CLR). At the top of each stack, you have the app-specific libraries that you use to build applications for your platform. For example, you could build a Windows Forms app on the .NET Framework, but not using the Xamarin platform, and vice versa for an iOS app.

In the middle of each stack you have the Base Class Libraries (BCLs). These are the fundamental .NET types you use in your apps on a daily basis: the int and string types, the file-reading APIs, the Task APIs, and so on. Although both .NET platforms have many similar types, they’re fundamentally different, so you can’t guarantee a type will exist on both platforms, or that it will expose the same methods and properties.

I’ve only discussed two platforms so far, the .NET Framework and Xamarin, but .NET has many different implementations. Windows also had the Windows 8/8.1 platform and the Universal Windows Platform (UWP). On phones, in addition to Xamarin, there was the Windows Phone 8.1 and Silverlight Phone platforms. The list goes on and on (Unity, .NET Compact Framework (CF), .NET Micro…)!

Each of these platforms uses a slightly different set of APIs (classes and methods) in their BCLs. Platforms have a certain number of similar APIs between them in their BCLs, but the intersection is patchy. On top of that, the libraries that make up the BCLs of a platform are fundamentally not interoperable. Any source code written for a given set of APIs must be specifically recompiled for each target platform.

Several years ago, Microsoft realized this sharding of .NET was a problem. Developers had to know a slightly different set of APIs for each platform and sharing code so that it could be used on more than one platform was a pain.

On top of that, the primary web development platform of the .NET Framework was showing its age. The software industry was moving toward small, lightweight, cloud-native frameworks that you could deploy in cross-platform environments. The centrally installed Windows-only .NET Framework was not designed for these scenarios. Microsoft set about developing a new framework, called “Project K” during development, which ultimately became .NET Core.

Introducing .NET Core

The .NET Core platform was Microsoft’s solution to the centrally installed, Windows-only .NET Framework. .NET Core is highly modular, can be deployed side-by-side with other .NET Core installations (or alternatively, distributed with the app), and is cross-platform. The term .NET Core is somewhat overloaded, in that it was used through development as a general umbrella term to describe a variety of changes. The .NET Core platform consists of

  • A cross-platform BCL—The BCL libraries of the .NET Core platform, historically called CoreFX. These contain all the primitive types and libraries for building .NET Core applications.
  • A new cross-platform runtime—The runtime for .NET Core, called CoreCLR, which executes .NET Core applications.
  • The .NET CLI tooling—The dotnet tool used for building and publishing apps.
  • The ASP.NET Core and EF Core libraries—The app-layer libraries, used to build ASP.NET Core applications.

These components make up the .NET Core platform and find their analogs to the various components that make up the .NET Framework and Xamarin platforms you saw in figure 1. By creating a new platform, Microsoft was able to maintain backward compatibility for apps that used the .NET Framework, while enabling new apps to be developed using .NET Core to take advantage of its cross-platform base and isolated deployment story.

Note You might be thinking, “Wait, they had too many .NET platforms, so they created another one?” If so, you’re on the ball. But luckily, with .NET Core came .NET Standard.

On its own, .NET Core would have meant yet another BCL of APIs for .NET developers to learn. But as part of the development of .NET Core, Microsoft introduced .NET Standard. .NET Standard, as the name suggests, ensured a standard set of APIs were available on every .NET platform. You no longer had to learn the specific set of APIs available for the flavor of .NET you were using; if you could use the .NET Standard APIs, you knew you’d be fine on multiple platforms. I’ll talk more about .NET Standard in the next post.

.NET Standard was a good stop-gap solution for writing code that could work on multiple platforms, but it didn’t address one fundamental issue: there were still multiple platforms. Every platform had its own separate code that must be maintained by Microsoft, despite being almost identical in many places.

Microsoft was innovating quickly in .NET Core, introducing new C# features such as Async Enumerables and Span<T>, as well as providing many performance improvements. Unfortunately, none of the other platforms could take advantage of these without significant work. Microsoft’s vision for tackling this head-on was One.NET.

With each new .NET release, the .NET blog details the vast low-level improvements made to .NET. These are fascinating if you are into that sort of thing! You can find the “Performance Improvements in .NET 7” blog post here: https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/.

The One .NET vision

In May 2019, Microsoft announced that the next major version of .NET Core after 3.0 would be .NET 5. This was the first step in their attempt to unify the .NET platform.

Originally, as I discussed earlier, you had to use .NET Framework to build Windows desktop apps, Xamarin to build iOS or Android apps, and .NET Core to build cross-platform web apps. Each app model was tied to the underlying platform and used a distinct BCL. The One .NET vision, which started with .NET 5, was to have a single .NET platform, with a single BCL, that can be used with every app model: Windows desktop apps, iOS or Android apps, as well as cross-platform web apps, as shown in figure 2.

Image showing the One.NET vision to unite the various plataforms.
Figure 2. .NET 5 started the vision to provide a single platform for running multiple app models. Instead of each app model requiring a separate .NET platform, with a separate BCL, all app models will be able to use the same underlying .NET platform and BCL.

Practically speaking, .NET 5 really was “just” the next version of .NET Core. .NET 5 added additional features (as did .NET 6 and .NET 7 subsequently), but fundamentally not much changed for most ASP.NET Core applications.

Note A common point of confusion is the name: .NET 5 or .NET 7 as opposed to .NET Core. The “Core” moniker was dropped to try and signify that “there is only one version of .NET now.” Also, version 4 was skipped, to avoid confusion between the new version and .NET Framework version 4. Hopefully this naming decision will pay off in the long run, even if it’s confusing retrospectively!

Microsoft intended to perform the unification of both the BCL and the infrastructure in .NET 5, but delays meant that this wasn’t complete until .NET 6. Microsoft also introduced .NET Multi-platform App UI (.NET MAUI) as a successor to Xamarin Forms, further unifying the platforms in .NET 7.

Tip You can read about .NET MAUI at https://learn.microsoft.com/dotnet/maui/.

With .NET 7 the One .NET vision is essentially complete. The hope is that basing all future development efforts on one platform will reduce duplication of effort and provide both greater stability and progress for the platform. With that in mind, Microsoft has committed to a regular release cadence, so you can easily plan how to keep your apps up to date as new versions of .NET are released.

The future: .NET 8 and beyond

As with many open-source projects, developing in the open is often associated with a faster release cycle than with the traditional .NET Framework. This was certainly the case with .NET Core, with new releases (major and minor) coming regularly for the first few years of development.

While many developers like this faster cadence and the new features it brings, it can lead to some uncertainty. Is it worth spending time upgrading to the latest version now if a new version is going to be released next week?

To counteract the potential churn and give users confidence in continued support, each .NET release now falls into one of two support tracks:

  • Long Term Support (LTS)—These releases are supported for three years from their first release.
  • Standard Term Support (STS)—Previously called Current releases, these releases are supported for 18 months from release.

Having two supported tracks leaves you with a simple choice: if you want more features choose STS releases; if you want longer between major upgrades, choose LTS.

Note Microsoft release patches for both STS and LTS releases regularly. These can include security fixes, so you must make sure to update your app’s packages and runtime regularly, regardless of which support track you choose. For more details on .NET support policies, see Microsoft’s “.NET and .NET Core Support Policy”: https://dotnet.microsoft.com/platform/support/policy/dotnet-core.

The two-track approach went some way to alleviating uncertainty, but it still left users unsure exactly when a new release would occur, and hence how long the STS version would be supported.

With .NET 5, Microsoft committed to a well-defined release cycle consisting of shipping a new major version of .NET every year, alternating between LTS releases and STS releases, as shown in figure 3. Minor updates are not intended to be common but may occur in interstitial months if required.

Image showing the timeline for releases of new .NET versions.
Figure 3. The timeline for releases of new .NET versions. A new .NET version will be released every year in November. Releases will alternate between Long Term Support (LTS) versions and Standard Term Support (STS) release versions.

With this timeline, you know how long a version of .NET will be supported. If you use an STS track release (such as .NET 7) you know you will be supported until six months after the release of .NET 8 in November 2023. As an LTS release, .NET 8.0 will be supported until November 2026.

The unification of multiple .NET platforms in .NET 7 means that there’s less need in future to share code between multiple platforms: that’s one of the big selling points of One .NET. Nevertheless, you will no doubt need to share code with existing legacy applications for many years, so code sharing is still a concern.

As I described previously, .NET Standard was introduced with .NET Core as a way of sharing code between .NET Core applications and existing legacy applications. In the next post, I'll dig into the details of .NET Standard, briefly discuss its predecessor, Portable Class Libraries, and look at the future of .NET Standard.

Summary

  • .NET has many different implementations, including the .NET Framework, Mono, and Unity. Each of these is a separate platform with separate Base Class Libraries (BCLs) and app models. .NET Core is another separate platform.
  • Each platform has a BCL that provides fundamental .NET types and classes, such as strings, file manipulation, and streams. Each platform has a slightly different BCL.
  • .NET 5 was the first step in unifying these platforms, most notably Mono (and hence Xamarin) and .NET Core, under the One .NET vision. With .NET 7, all the main app models currently associated with other platforms are available.
  • .NET 5 unified the code bases for the Mono and .NET Core BCLs. In .NET 6, the runtime and tooling was also unified, completing the One .NET vision. You can now build web, desktop, and mobile apps and more with a single .NET platform, .NET 7.
  • .NET will see a new major release every year. These will alternate between Long Term Support (LTS) releases, which receive 3 years of support, and Standard Term Support (STS) releases, which receive 18 months of support.

A reminder that this content originally came from the latest edition of my book, ASP.NET Core in Action, Third Edition. Get a 35% discount by entering the code au35loc into the discount code box at checkout at manning.com. You'll also get ebook copies of the first and second editions, free!

Andrew Lock | .Net Escapades
Want an email when
there's new posts?