Announcing .NET Core 2.1 Preview 1

Today, we are announcing .NET Core 2.1 Preview 1. It is the first public release of .NET Core 2.1. We have great improvements that we want to share and that we would love to get your feedback on, either in the comments or at dotnet/core #1297.

To everyone that helped with the release, thank you very much. We couldn’t have gotten to this spot without you and we’ll continue to need your help as we work together towards .NET Core 2.1 RTM.

Let’s look at the many improvements that are part of the .NET Core 2.1 Preview 1 release. As big a release as .NET Core 2.0 was, you should find multiple improvements that will want to make you upgrade.

Themes

The .NET Core 2.1 release, across .NET Core, ASP.NET Core and EF Core is intended to improve the product across the following themes:

Faster Build Performance

Close gaps in ASP.NET Core and EF Core

Improve compatibility with .NET Framework

GDPR and Security

Microservices and Azure

More capable Engineering System

Some improvements for these themes are not yet in Preview 1. These themes are guiding our investments across the .NET Core 2.1 release.

Global Tools

.NET Core now has a new deployment and extensibility mechanism for tools. This new experience is very similar to and was inspired by NPM global tools.

You can try out .NET Core Global Tools for yourself (after you’ve installed .NET Core 2.1 Preview 1) with a sample tool called dotnetsay that we published, using the following commands:

dotnet install tool -g dotnetsaydotnetsay

Once you install dotnetsay, you can then use it directly by just typing dotnetsay in your command prompt or terminal. You can close terminal sessions, switch drives in the terminal, or reboot your machine and the command will still be there. dotnetsay is now in your path. Check %USERPROFILE%\.dotnet\tools or ~/.dotnet/tools (as appropriate) to see the tools installation location on your machine.

.NET Core tools are .NET Core console apps that are packaged and acquired as NuGet packages. By default, these tools are framework-dependent applications and include all of their NuGet dependencies. This means that a given global tool will run on any operating system or chip architecture by default. You might need an existing tool on a new version of Linux. As long as .NET Core works there, you should be able to run the tool.

At present, .NET Core Tools only support global install and require the -g argument to be installed. We’re working on various forms of local install, too, but those are not ready in preview 1.

We expect a whole new ecosystem of tools to establish itself for .NET. Some of these tools will be specific to .NET Core development and many of them will be general in nature. The tools are deployed to NuGet feeds. By default, the dotnet tool install command looks for tools on NuGet.org.

If you are curious about dotnetsay, it is modeled after docker/whalesay, which is modeled after cowsay. dotnetsay is really just dotnet-bot, who is one of our busiest developers!

Build Performance Improvements

Build-time performance is much improved in .NET Core 2.1, particularly for incremental builds. These improvements apply to both dotnet build on the commandline and to builds in Visual Studio. We’ve made improvements in the CLI tools and in MSBuild in order to make the tools deliver a much faster experience.

The following chart provides concrete numbers on the improvements that you can expect from the new release. You can see two different workloads with numbers for .NET Core 2.0, .NET Core 2.1 Preview 1 and where we aspire to land for .NET Core RTW.

You can try building the same code yourself at mikeharder/dotnet-cli-perf. We’d be curious if you get similar results. Note that the improvements are for incremental builds, so you’ll only see benefits after the 2nd build.

Minor-Version Roll-forward

You will now be able to run .NET Core applications on later runtime versions, within the same major version range. For example, you will be able to run .NET Core 2.0 applications on .NET Core 2.1 or .NET Core 2.1 applications on .NET Core 2.5 (if we ever ship such a version). The roll-forward behavior is for minor versions only. For example, a .NET Core 2.x application will never automatically roll forward to .NET Core 3.0 or later.

If the expected .NET Core version is available, it is used. The roll-forward behavior is only relevant if the expected .NET Core version is not available in a given environment.

You can disable minor version roll-forward with

Environment variable: DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=0

runtimeconfig.json: rollForwardOnNoCandidateFx=0

CLI: –roll-forward-on-no-candidate-fx=0

Sockets Performance and HTTP Managed Handler

We made major improvements to sockets in .NET Core 2.1. Sockets are the basis of both outgoing and incoming networking communication. In .NET Core 2.0, the ASP.NET Kestrel Web Server and HttpClient use native sockets, not the .NET Socket class. We are in the process of changing that, instead basing our higher-level networking APIs on .NET sockets.

We made three significant performance improvements for sockets (and other smaller ones) in Preview 1:

You can opt-in to using the SocketHTTPHandler in one the following ways with Preview 1:

Environment variable: COMPlus_UseManagedHttpClientHandler=true

AppContext: System.Net.Http.UseManagedHttpClientHandler=true

In Preview 2 (or GitHub master branch), you’ll be able to new up the handler, as you’d expect: new HttpClient(new SocketsHttpHandler()). We are also thinking about making the new handler the default, and enable the existing native handler (based on libcurl and WinHTTP) as optional.

You might wonder how sockets improvements can be shared between incoming and outgoing scenarios, because they feel so different. It’s actually pretty simple. If you’re a client, you do a connect on a server. if you’re a server, you listen and wait for connections. Once that connection is established, data can flow both ways, and that’s critical from a perf point of view. As a result, these socket improvements should improve both scenarios.

Span<T>, Memory<T> and friends

We are on the verge of introducing a new set of types for using arrays and other types of memory that is much more efficient. They are included in Preview 1. Today, if you want to pass the first 1000 elements of a 10,000 element array, you need to make a copy of those 1000 elements and pass that copy to your caller. That operation is expensive in both time and space. The new Span<T> type enables you to provide a virtual view of that array without the time or space cost. It’s also a struct, which means that there is no allocation cost either.

Span<T> and related types offer a uniform representation of memory from a multitude of different sources, such as arrays, stack allocation, and native code. With its slicing capabilities, it obviates the need for expensive copying and allocation in many scenarios, such as string manipulation, buffer management, etc, and provides a safe alternative to unsafe code. We expect usage of these types to start off in performance critical scenarios, but then transition to replacing arrays as the primary way of managing large blocks of data in .NET.

In terms of usage, you can create a Span<T> from an array:

From there, you can easily and efficiently create a span to represent/point to just a subset of this array, utilizing an overload of the span’s Slice method. From there you can index into the resulting span to write and read data in the relevant portion of the original array:

Windows Compatibility Pack

When you port existing code from the .NET Framework to .NET Core, you can use the new Windows Compatibility Pack. It provides access to an additional 20,000 APIs, compared to what is available in .NET Core. This includes System.Drawing, EventLog, WMI, Performance Counters, and Windows Services.

The following examples demonstrates accessing the Windows registry with APIs provided by the Windows Compatibility Pack.

Switched from debian:stretch to debian:stretch-slim for runtime images. (x64 and ARM32).

Dropped debian:jessie (runtime and SDK).

These changes were based, in part, on two repeated pieces of feedback that we heard over the last six months.

Provide smaller images, particularly for the runtime.

Provide images with less surface area and/or more frequently updated (than Debian), from a vulnerability standpoint.

We also rewrote the .NET Core Docker Samples instructions and code. The samples provide better instructions and implement more scenarios like unit testing and using docker registries. We hope you find the samples helpful and we plan to continue to expand them. Tell us what you’d like to see us add to make .NET Core and Docker work better together.

Closing

Thanks for trying out .NET Core 2.1 Preview 1. Please try out your existing applications with .NET Core 2.1 Preview 1. And please try out the new features that are introduced in this post. We’ve put a lot of effort into making them right but we need your feedback to take them across the finish line, for our final release.

Once again, thanks to everyone that contributed to the release. We appreciate all of the issues and PRs that you’ve contributed that have helped make this first preview release available.

There are also some other proof-reading errors on this page. I’d gladly help fixing them, but it would be much more convenient both for me and you if the source code to the blog post was available on GitHub so I can just send you a PR. 🙂 Please consider fixing!