At connect(), we announced that .NET Core will be entirely released as open source software. I also promised to follow up with more details on .NET Core. In this post, I’ll provide an overview of .NET Core, how we’re going to release it, how it relates to the .NET Framework, and what this means for cross-platform and open source development.
Here the second part of the article focused on .NET Core:
Enter .NET Core
All these aspects caused us to rethink and change the approach of modelling the .NET platform moving forward. This resulted in the creation of .NET Core:
.NET Core is a modular implementation that can be used in a wide variety of verticals, scaling from the data center to touch based devices, is available as open source, and is supported by Microsoft on Windows, Linux and Mac OSX.
Let me go into a bit more detail of how .NET Core looks like and how it addresses the issues I discussed earlier.
Unified implementation for .NET Native and ASP.NET
When we designed .NET Native it was clear that we can’t use the .NET Framework as the foundation for the framework class libraries. That’s because .NET Native essentially merges the framework with the application, and then removes the pieces that aren’t needed by the application before it generates the native code (I’m grossly simplifying this process here. For more details, take a look at this deep dive). As I explained earlier, the .NET Framework implementation isn’t factored which makes it quite challenging for a linker to reduce how much of the framework gets compiled into the application – the dependency closure is just too large.
ASP.NET 5 faced similar challenges. Although it doesn’t use .NET Native one of the goals of the new ASP.NET 5 web stack was to provide an XCOPY deployable stack so that web developers don’t have coordinate with their IT department in order to take dependencies on later versions. In that scenario it’s also important to minimize the size of the framework as it needs to be deployed alongside the application.
.NET Core is essentially a fork of the NET Framework whose implementation is also optimized around factoring concerns. Even though the scenarios of .NET Native (touch based devices) and ASP.NET 5 (server side web development) are quite different, we were able to provide a unified Base Class Library (BCL).
The API surface area for the .NET Core BCL is identical for both .NET Native as well ASP.NET 5. At the bottom of the BCL we have a very thin layer that is specific to the .NET runtime. We’ve currently two implementations: one is specific to the .NET Native runtime and one that is specific to CoreCLR, which is used by ASP.NET 5. However, that layer doesn’t change very often. It contains types like String and Int32. The majority of the BCL are pure MSIL assemblies that can be shared as-is. In other words, the APIs don’t just look the same – they share the same implementation. For example, there is no reason to have different implementations for collections.
On top of the BCL, there are app-model specific APIs. For instance, the .NET Native side provides APIs that are specific to Windows client development, such as WinRT interop. ASP.NET 5 adds APIs such as MVC that are specific to server- side web development.
We think of .NET Core as not being specific to either .NET Native nor ASP.NET 5 – the BCL and the runtimes are general purpose and designed to be modular. As such, it forms the foundation for all future .NET verticals.
NuGet as a first class delivery vehicle
In contrast to the .NET Framework, the .NET Core platform will be delivered as a set of NuGet packages. We’ve settled on NuGet because that’s where the majority of the library ecosystem already is.
In order to continue our effort of being modular and well factored we don’t just provide the entire .NET Core platform as a single NuGet package. Instead, it’s a set of fine grained NuGet packages:
For the BCL layer, we’ll have a 1-to-1 relationship between assemblies and NuGet packages.
Moving forward, the NuGet package will have the same name as the assembly. For example, immutable collections will no longer be delivered in a NuGet package called Microsoft.Bcl.Immutable but instead be in a package called System.Collections.Immutable.
In addition, we’ve decided to use semantic versioning for our assembly versioning. The version number of the NuGet package will align with the assembly version.
The alignment of naming and versioning between assemblies and packages help tremendously with discovery. There is no longer a mystery which NuGet packages contains System.Foo, Version=18.104.22.168 – it’s provided by the System.Foo package in version 1.2.3.
NuGet allows us to deliver .NET Core in an agile fashion. So if we provide an upgrade to any of the NuGet packages, you can simply upgrade the corresponding NuGet reference.
Delivering the framework itself on NuGet also removes the difference between expressing 1st party .NET dependencies and 3rd party dependencies – they are all NuGet dependencies. This enables a 3rd party package to express, for instance, that they need a higher version of the System.Collections library. Installing this 3rd party package can now prompt you to upgrade your reference to System.Collections. You don’t have to understand the dependency graph – you only need to consent making changes to it.
The NuGet based delivery also turns the .NET Core platform into an app-local framework. The modular design of .NET Core ensures that each application only needs to deploy what it needs. We’re also working on enabling smart sharing if multiple applications use the same framework bits. However, the goal is to ensure that each application is logically having its own framework so that upgrading doesn’t interfere with other applications running on the same machine.
Our decision to use NuGet as a delivery mechanism doesn’t change our commitment to compatibility. We continue to take compatibility extremely seriously and will not perform API or behavioral breaking changes once a package is marked as stable. However, the app-local deployment ensures that the rare case where a change that is considered additive breaks an application is isolated to development time only. In other words, for .NET Core these breaks can only occur after you upgraded a package reference. In that very moment, you have two options: addressing the compat glitch in your application or rolling back to the previous version of the NuGet package. But in contrast to the .NET Framework those breaks will not occur after you deployed the application to a customer or the production server.
The NuGet deployment model enables agile releases and faster upgrades. However, we don’t want to compromise the one-stop-shop experience that the .NET Framework provides today.
One of the great things of the .NET Framework is that it ships as a holistic unit, which means that Microsoft tested and supports all components as a single entity. For .NET Core we’ll provide the same experience. We’ll create the notion of a .NET Core distribution. This is essentially just a snapshot of all the packages in the specific version we tested them.
The idea is that our teams generally own individual packages. Shipping a new version of the team’s package only requires that the team tests their component, in the context of the components they depend on. Since you’ll be able to mix- and-match NuGet packages there can obviously be cases where certain combinations of components don’t play well together. Distributions will not have that problem because all components are tested in combination.
We expect distributions to be shipped at a lower cadence than individual packages. We are currently thinking of up to four times a year. This allows for the time it will take us to run the necessary testing, fixing and sign off.
Although .NET Core is delivered as a set of NuGet packages it doesn’t mean that you have to download packages each time you need to create a project. We’ll provide an offline installer for distributions and also include them with Visual Studio so that creating new projects will be as fast as today and not require internet connectivity in the development process.
While app-local deployment is great for isolating the impact of taking dependencies on newer features it’s not appropriate for all cases. Critical security fixes must be deployed quickly and holistically in order to be effective. We are fully committed to making security fixes as we always have for .NET.
In order to avoid the compatibility issues we have seen in the past with centralized updates to the .NET Framework it’s essential that these only target the security vulnerabilities. Of course, there is still a small chance that those break existing applications. That’s why we only do this for truly critical issues where it’s acceptable to cause a very small set of apps to no longer work rather than having all apps run with the vulnerability.
Foundation for open source and cross platform
In order to take .NET cross platform in a sustainable way we decided to open source .NET Core.
From past experience we understand that the success of open source is a function of the community around it. A key aspect to this is an open and transparent development process that allows the community to participate in code reviews, read design documents, and contribute changes to the product.
Open source enables us to extend the .NET unification to cross platform development. It actively hurts the ecosystem if basic components like collections need to be implemented multiple times. The goal of .NET Core is having a single code base that can be used to build and support all the platforms, including Windows, Linux and Mac OSX.
Of course, certain components, such as the file system, require different implementations. The NuGet deployment model allows us to abstract those differences away. We can have a single NuGet package that provides multiple implementations, one for each environment. However, the important part is that this is an implementation detail of this component. All the consumers see a unified API that happens to work across all the platforms.
Another way to look at this is that open source is a continuation of our desire to release .NET components in an agile fashion:
- Open Source offers quasi real-time communication for the implementation and overall direction
- Releasing packages to NuGet.org offers agility at the component level
- Distributions offer agility at the platform level
Having all three elements allows us to offer a broad spectrum of agility and maturity.
Relationship of .NET Core with existing platforms
Although we’ve designed .NET Core so that it will become the foundation for all future stacks, we’re very much aware of the dilemma of creating the “one universal stack” that everyone can use:
We believe we found a good balance between laying the foundation for the future while maintaining great interoperability with the existing stacks. I’ll go into more detail by looking at several of these platforms.
.NET Framework 4.6
The .NET Framework is still the platform of choice for building rich desktop applications and .NET Core doesn’t change that.
For Visual Studio 2015 our goal is to make sure that .NET Core is a pure subset of the .NET Framework. In other words, there wouldn’t be any feature gaps. After Visual Studio 2015 is released our expectation is that .NET Core will version faster than the .NET Framework. This means that there will be points in time where a feature will only be available on the .NET Core based platforms.
We’ll continue to release updates to .NET Framework. Our current thinking is that the release cadence will roughly be the same as today, which is about once a year. In these updates, we’ll bring the innovations that we made in .NET Core to the .NET Framework. We’ll not just blindly port all the feature work, though – it will be based on a cost-benefit analysis. As I pointed out, even additive changes to the .NET Framework can cause issues for existing applications. Our goal is to minimize API and behavioral differences while not breaking compatibility with existing .NET Framework applications.
There are also investments that are exclusively being made for the .NET Framework such as the work we announced in the WPF Roadmap.
Many of you asked what the .NET Core cross platform story means for Mono. The Mono project is essentially an open source re-implementation of the .NET Framework. As such, it shares the richness of the APIs with the .NET Framework but it also shares some of its problems, specifically around the implementation factoring.
Mono is alive and well with a large ecosystem on top. That’s why, independent of .NET Core, we also released parts of the .NET Framework Reference Source under an open source friendly license on GitHub. This was done to allow the Mono community to close the gaps between the .NET Framework and Mono by using the same code. However, due to the complexity of the .NET Framework we’re not setup to run it as an open source project on GitHub. In particular, we’re unable to accept pull requests for it.
Another way to look at it: The .NET Framework has essentially two forks. One fork is provided by Microsoft and is Windows only. The other fork is Mono which you can use on Linux and Mac.
With .NET Core we’re able to develop an entire .NET stack as a full open source project. Thus, having to maintain separate forks will no longer be necessary: together with the Mono community we’ll make .NET Core great for Windows, Linux and Mac OSX. This also enables the Mono community to innovate on top of the leaner .NET Core stack as well as taking it to environments that Microsoft isn’t interested in.
Windows Store & Windows Phone
Both the Windows Store 8.1 and Windows Phone 8.1 platforms are much smaller subsets of the .NET Framework. However, they are also a subset of .NET Core. This allows us to use .NET Core as the underlying implementation for both of these platforms moving forward. So if you’re developing for those platforms you are able to directly consume all innovations without having to wait for an updated framework.
It also means that the number of BCL APIs available on both platforms will be identical to the ones you can see in ASP.NET 5 today. For example, this includes non-generic collections. This will make it much easier for you to bring existing code that runs on top of the .NET Framework into the touch-based application experience.
Another obvious side effect is that the BCL APIs in Windows Store and Windows Phone are fully converged and will remain converged as the underlying .NET platform is now both powered by .NET Core.
Sharing code between .NET Core and other .NET platforms
Since .NET Core forms the foundation for all future .NET platforms code sharing with .NET Core based platforms has become friction free.
This raises the question how code sharing works with platforms that aren’t based on .NET Core, such as the .NET Framework. The answer is: it’s the same as today, you can continue to use portable class libraries and shared projects:
- Portable class libraries are great when your common code is platform-independent as well as for reusable libraries where the platform-specific code can be factored out.
- Shared projects are great when your common code has a few bits of platform-specific code, since you can adapt it with
For more details on how choose between the two, take a look at this blog post.
Moving forward, portable class libraries will also support targeting .NET Core based platforms. The only difference is that if you only target .NET Core based platforms you don’t get a fixed API set. Instead, it’s based on NuGet packages that you can upgrade at will.
If you also target at least one platform that isn’t based on .NET Core, you’re constrained by the APIs that can be shared with it. In this mode, you’re still able to upgrade NuGet packages but you may get prompted to select higher platform versions or completely drop support for them.
This approach allows you to co-exist in both worlds while still reaping the benefits that .NET Core brings.
The .NET Core platform is a new .NET stack that is optimized for open source development and agile delivery on NuGet. We’re working with the Mono community to make it great on Windows, Linux and Mac, and Microsoft will support it on all three platforms.
We’re retaining the values that the .NET Framework brings to enterprise class development. We’ll offer .NET Core distributions that represent a set of NuGet packages that we tested and support together. Visual Studio remains your one- stop-shop for development. Consuming NuGet packages that are part of a distribution doesn’t require an internet connection.
We acknowledge our responsibility and continue to support shipping critical security fixes without requiring any work from the application developer, even if the affected component is exclusively distributed as NuGet package.