What's new in .NET Core 2.1
.NET Core 2.1 includes enhancements and new features in the following areas:
Tooling
The .NET Core 2.1 SDK (v 2.1.300), the tooling included with .NET Core 2.1, includes the following changes and enhancements:
Build performance improvements
A major focus of .NET Core 2.1 is improving build-time performance, particularly for incremental builds. These performance improvements apply to both command-line builds using dotnet build
and to builds in Visual Studio. Some individual areas of improvement include:
For package asset resolution, resolving only assets used by a build rather than all assets.
Caching of assembly references.
Use of long-running SDK build servers, which are processes that span across individual
dotnet build
invocations. They eliminate the need to JIT-compile large blocks of code every timedotnet build
is run. Build server processes can be automatically terminated with the following command:dotnet buildserver shutdown
New CLI commands
A number of tools that were available only on a per project basis using DotnetCliToolReference
are now available as part of the .NET Core SDK. These tools include:
dotnet watch
provides a file system watcher that waits for a file to change before executing a designated set of commands. For example, the following command automatically rebuilds the current project and generates verbose output whenever a file in it changes:dotnet watch -- --verbose build
Note the
--
option that precedes the--verbose
option. It delimits the options passed directly to thedotnet watch
command from the arguments that are passed to the childdotnet
process. Without it, the--verbose
option applies to thedotnet watch
command, not thedotnet build
command.For more information, see Develop ASP.NET Core apps using dotnet watch.
dotnet dev-certs
generates and manages certificates used during development in ASP.NET Core applications.dotnet user-secrets
manages the secrets in a user secret store in ASP.NET Core applications.dotnet sql-cache
creates a table and indexes in a Microsoft SQL Server database to be used for distributed caching.dotnet ef
is a tool for managing databases, DbContext objects, and migrations in Entity Framework Core applications. For more information, see EF Core .NET Command-line Tools.
Global Tools
.NET Core 2.1 supports Global Tools -- that is, custom tools that are available globally from the command line. The extensibility model in previous versions of .NET Core made custom tools available on a per project basis only by using DotnetCliToolReference
.
To install a Global Tool, you use the dotnet tool install command. For example:
dotnet tool install -g dotnetsay
Once installed, the tool can be run from the command line by specifying the tool name. For more information, see .NET Core Global Tools overview.
Tool management with the dotnet tool
command
In .NET Core 2.1 SDK, all tools operations use the dotnet tool
command. The following options are available:
dotnet tool install
to install a tool.dotnet tool update
to uninstall and reinstall a tool, which effectively updates it.dotnet tool list
to list currently installed tools.dotnet tool uninstall
to uninstall currently installed tools.
Roll forward
All .NET Core applications starting with .NET Core 2.0 automatically roll forward to the latest minor version installed on a system.
Starting with .NET Core 2.0, if the version of .NET Core that an application was built with is not present at run time, the application automatically runs against the latest installed minor version of .NET Core. In other words, if an application is built with .NET Core 2.0, and .NET Core 2.0 is not present on the host system but .NET Core 2.1 is, the application runs with .NET Core 2.1.
Important
This roll-forward behavior doesn't apply to preview releases. By default, it also doesn't apply to major releases, but this can be changed with the settings below.
You can modify this behavior by changing the setting for the roll-forward on no candidate shared framework. The available settings are:
0
- disable minor version roll-forward behavior. With this setting, an application built for .NET Core 2.0.0 will roll forward to .NET Core 2.0.1, but not to .NET Core 2.2.0 or .NET Core 3.0.0.1
- enable minor version roll-forward behavior. This is the default value for the setting. With this setting, an application built for .NET Core 2.0.0 will roll forward to either .NET Core 2.0.1 or .NET Core 2.2.0, depending on which one is installed, but it will not roll forward to .NET Core 3.0.0.2
- enable minor and major version roll-forward behavior. If set, even different major versions are considered, so an application built for .NET Core 2.0.0 will roll forward to .NET Core 3.0.0.
You can modify this setting in any of three ways:
Set the
DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX
environment variable to the desired value.Add the following line with the desired value to the .runtimeconfig.json file:
"rollForwardOnNoCandidateFx" : 0
When using the .NET CLI, add the following option with the desired value to a .NET command such as
run
:dotnet run --rollForwardOnNoCandidateFx=0
Patch version roll forward is independent of this setting and is done after any potential minor or major version roll forward is applied.
Deployment
Self-contained application servicing
dotnet publish
now publishes self-contained applications with a serviced runtime version. When you publish a self-contained application with the .NET Core 2.1 SDK (v 2.1.300), your application includes the latest serviced runtime version known by that SDK. When you upgrade to the latest SDK, you'll publish with the latest .NET Core runtime version. This applies for .NET Core 1.0 runtimes and later.
Self-contained publishing relies on runtime versions on NuGet.org. You do not need to have the serviced runtime on your machine.
Using the .NET Core 2.0 SDK, self-contained applications are published with the .NET Core 2.0.0 runtime unless a different version is specified via the RuntimeFrameworkVersion
property. With this new behavior, you'll no longer need to set this property to select a higher runtime version for a self-contained application. The easiest approach going forward is to always publish with .NET Core 2.1 SDK (v 2.1.300).
For more information, see Self-contained deployment runtime roll forward.
Windows Compatibility Pack
When you port existing code from the .NET Framework to .NET Core, you can use the Windows Compatibility Pack. It provides access to 20,000 more APIs than are available in .NET Core. These APIs include types in the System.Drawing namespace, the EventLog class, WMI, Performance Counters, Windows Services, and the Windows registry types and members.
JIT compiler improvements
.NET Core incorporates a new JIT compiler technology called tiered compilation (also known as adaptive optimization) that can significantly improve performance. Tiered compilation is an opt-in setting.
One of the important tasks performed by the JIT compiler is optimizing code execution. For little-used code paths, however, the compiler may spend more time optimizing code than the runtime spends running unoptimized code. Tiered compilation introduces two stages in JIT compilation:
A first tier, which generates code as quickly as possible.
A second tier, which generates optimized code for those methods that are executed frequently. The second tier of compilation is performed in parallel for enhanced performance.
You can opt in to tiered compilation in either of two ways.
To use tiered compilation in all projects that use the .NET Core 2.1 SDK, set the following environment variable:
COMPlus_TieredCompilation="1"
To use tiered compilation on a per-project basis, add the
<TieredCompilation>
property to the<PropertyGroup>
section of the MSBuild project file, as the following example shows:<PropertyGroup> <!-- other property definitions --> <TieredCompilation>true</TieredCompilation> </PropertyGroup>
API changes
Span<T>
and Memory<T>
.NET Core 2.1 includes some new types that make working with arrays and other types of memory much more efficient. The new types include:
Without these types, when passing such items as a portion of an array or a section of a memory buffer, you have to make a copy of some portion of the data before passing it to a method. These types provide a virtual view of that data that eliminates the need for the additional memory allocation and copy operations.
The following example uses a Span<T> and Memory<T> instance to provide a virtual view of 10 elements of an array.
using System;
class Program
{
static void Main()
{
int[] numbers = new int[100];
for (int i = 0; i < 100; i++)
{
numbers[i] = i * 2;
}
var part = new Span<int>(numbers, start: 10, length: 10);
foreach (var value in part)
Console.Write($"{value} ");
}
}
// The example displays the following output:
// 20 22 24 26 28 30 32 34 36 38
Module Program
Sub Main()
Dim numbers As Integer() = New Integer(99) {}
For i As Integer = 0 To 99
numbers(i) = i * 2
Next
Dim part = New Memory(Of Integer)(numbers, start:=10, length:=10)
For Each value In part.Span
Console.Write($"{value} ")
Next
End Sub
End Module
' The example displays the following output:
' 20 22 24 26 28 30 32 34 36 38
Brotli compression
.NET Core 2.1 adds support for Brotli compression and decompression. Brotli is a general-purpose lossless compression algorithm that is defined in RFC 7932 and is supported by most web browsers and major web servers. You can use the stream-based System.IO.Compression.BrotliStream class or the high-performance span-based System.IO.Compression.BrotliEncoder and System.IO.Compression.BrotliDecoder classes. The following example illustrates compression with the BrotliStream class:
public static Stream DecompressWithBrotli(Stream toDecompress)
{
MemoryStream decompressedStream = new MemoryStream();
using (BrotliStream decompressionStream = new BrotliStream(toDecompress, CompressionMode.Decompress))
{
decompressionStream.CopyTo(decompressedStream);
}
decompressedStream.Position = 0;
return decompressedStream;
}
Public Function DecompressWithBrotli(toDecompress As Stream) As Stream
Dim decompressedStream As New MemoryStream()
Using decompressionStream As New BrotliStream(toDecompress, CompressionMode.Decompress)
decompressionStream.CopyTo(decompressedStream)
End Using
decompressedStream.Position = 0
Return decompressedStream
End Function
The BrotliStream behavior is the same as DeflateStream and GZipStream, which makes it easy to convert code that calls these APIs to BrotliStream.
New cryptography APIs and cryptography improvements
.NET Core 2.1 includes numerous enhancements to the cryptography APIs:
System.Security.Cryptography.Pkcs.SignedCms is available in the System.Security.Cryptography.Pkcs package. The implementation is the same as the SignedCms class in the .NET Framework.
New overloads of the X509Certificate.GetCertHash and X509Certificate.GetCertHashString methods accept a hash algorithm identifier to enable callers to get certificate thumbprint values using algorithms other than SHA-1.
New Span<T>-based cryptography APIs are available for hashing, HMAC, cryptographic random number generation, asymmetric signature generation, asymmetric signature processing, and RSA encryption.
The performance of System.Security.Cryptography.Rfc2898DeriveBytes has improved by about 15% by using a Span<T>-based implementation.
The new System.Security.Cryptography.CryptographicOperations class includes two new methods:
FixedTimeEquals takes a fixed amount of time to return for any two inputs of the same length, which makes it suitable for use in cryptographic verification to avoid contributing to timing side-channel information.
ZeroMemory is a memory-clearing routine that cannot be optimized.
The static RandomNumberGenerator.Fill method fills a Span<T> with random values.
The System.Security.Cryptography.Pkcs.EnvelopedCms is now supported on Linux and macOS.
Elliptic-Curve Diffie-Hellman (ECDH) is now available in the System.Security.Cryptography.ECDiffieHellman class family. The surface area is the same as in the .NET Framework.
The instance returned by RSA.Create can encrypt or decrypt with OAEP using a SHA-2 digest, as well as generate or validate signatures using RSA-PSS.
Sockets improvements
.NET Core includes a new type, System.Net.Http.SocketsHttpHandler, and a rewritten System.Net.Http.HttpMessageHandler, that form the basis of higher-level networking APIs. System.Net.Http.SocketsHttpHandler, for example, is the basis of the HttpClient implementation. In previous versions of .NET Core, higher-level APIs were based on native networking implementations.
The sockets implementation introduced in .NET Core 2.1 has a number of advantages:
A significant performance improvement when compared with the previous implementation.
Elimination of platform dependencies, which simplifies deployment and servicing.
Consistent behavior across all .NET Core platforms.
SocketsHttpHandler is the default implementation in .NET Core 2.1. However, you can configure your application to use the older HttpClientHandler class by calling the AppContext.SetSwitch method:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", False)
You can also use an environment variable to opt out of using sockets implementations based on SocketsHttpHandler. To do this, set the DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER
to either false
or 0.
On Windows, you can also choose to use System.Net.Http.WinHttpHandler, which relies on a native implementation, or the SocketsHttpHandler class by passing an instance of the class to the HttpClient constructor.
On Linux and macOS, you can only configure HttpClient on a per-process basis. On Linux, you need to deploy libcurl if you want to use the old HttpClient implementation. (It is installed with .NET Core 2.0.)
Breaking changes
For information about breaking changes, see Breaking changes for migration from version 2.0 to 2.1.