我们很高兴可以发布 .NET Core 2.1。这次更新包括对性能的改进,对运行时和工具的改进。还包含一种以 NuGet 包的形式部署工具的新方法。我们添加了一个名为 Span<T>
的新基元类型,它可以在没有内存分配的情况下对数据进行操作。还有许多其他新的 API,专注于密码学,压缩和 Windows 兼容性。它是第一个支持 Alpine Linux 和 ARM32 芯片的版本。您今天就可以开始将现有项目更新至 .NET Core 2.1 了。 该版本与 .NET Core 2.0 兼容,更新会变得很简单。
ASP.NET Core 2.1 和 Entity Framework Core 2.1 也已在今天发布。
您可以在 Windows,MacOS 和 Linux 上下载并开始使用 .NET Core 2.1:
- .NET Core 2.1 SDK (includes the runtime)
- .NET Core 2.1 Runtime
.NET Core 和 ASP.NET Core 的 Docker 镜像也已经可用: microsoft/dotnet
本月早些时候召开了 Build 2018 大会。我们对 .NET Core 进行了几次深入的演示。可以在 Channel9 上查看 Build 2018 sessions for .NET。
您可以在 .NET Core 2.1 发行说明 中看到该发行版的完整详细信息。发行说明中包含相关说明、已知问题和解决方法。请在评论中或dotnet/core #1614 中提交您发现的任何问题
感谢为 .NET Core 2.1 做出贡献的每个人。您已经帮助 .NET Core 成为更好的产品!
Long-term Support 长期支持
.NET Core 2.1 将是一个长期支持(LTS)版本。这意味着它会支持三年。我们建议您将 .NET Core 2.1 作为 .NET Core 开发的新标准。
我们打算在未来 2-3 个月内发布少量重要更新,然后正式将 .NET Core 2.1 作为 LTS 发布。之后,更新将针对安全性、可靠性以及添加平台支持(例如 Ubuntu 18.10)。我们建议您现在开始采用 .NET Core 2.1。对于处于活跃开发状态的应用程序,没有理由推迟将 .NET Core 2.1 部署到生产环境中。对于不活跃开发状态的应用程序,我们建议您等待部署,直到将 .NET Core 2.1 声明为 LTS。
有以下几个原因升级到 .NET Core 2.1:
- 长期支持(LTS)。
- 卓越的性能和质量。
- 新的平台支持,例如:Ubuntu 18.04,Alpine,ARM32。
- 更容易的在项目文件中管理平台依赖关系和自包含应用程序发布。
我们收到很多希望将 .NET Core 2.0 作为 LTS 版本的请求。事实上,那是我们原来的计划。我们选择等待,直到我们解决了管理平台依赖性的各种挑战(上面的最后一点)。平台依赖管理是 .NET Core 1.0 中的一个重要问题,并且随着每个版本的逐步改进。例如,您会注意到 ASP.NET Core 软件包引用不再包含 .NET Core 2.1 的版本号。
Platform Support 平台支持
.NET Core 2.1 支持以下操作系统:
- Windows Client: 7, 8.1, 10 (1607+)
- Windows Server: 2008 R2 SP1+
- macOS: 10.12+
- RHEL: 6+
- Fedora: 26+
- Ubuntu: 14.04+
- Debian: 8+
- SLES: 12+
- openSUSE: 42.3+
- Alpine: 3.7+
芯片支持如下:
- Windows,MacOS 和 Linux上 的 x64
- Windows 上的 x86
- Linux 上的 ARM32(Ubuntu 18.04+,Debian 9+)
注意:Raspberry Pi 2+ 支持 .NET Core 2.1。 它在 Pi Zero 或其他使用 ARMv6 芯片的设备上不受支持。.NET Core 需要 ARMv7 或 ARMv8 芯片,如 ARM Cortex-A53。
.NET Core Tools 工具
.NET Core tools 现在有一个新的部署和扩展机制。这种新体验与 NPM 全局工具非常相似,同时受到 NPM 的启发。您可以通过查看 dotnetsay tools 示例 来创建自己的全局 tools 。
您可以使用以下命令尝试使用 dotnetsay :
dotnet tool install -g dotnetsay
dotnetsay
.NET Core tools 是一个 .NET Core 控制台应用程序,它们是作为 NuGet 包来打包和获取的。默认情况下,这些 tools 是依赖于框架的应用程序,并包含其所有的 NuGet 依赖项。这意味着 .NET Core tools 默认运行在所有支持 .NET Core 的操作系统和芯片架构上,并带有一组二进制文件。默认情况下,dotnet tool install
命令会在 NuGet.org 上查找 tools 。您也可以改用您自己的 NuGet Feed。
目前,.NET Core Tools 仅支持全局安装且需要 -g 参数。我们也在开展各种形式的本地安装,并计划在后续版本中提供。
我们期望一个全新的 tools 生态系统能够为它自身服务。 @natemcmaster 维护了一个 dotnet tools 列表。你也可以看看他的 dotnet-serve 工具。
以下现有的 DotNetCliReferenceTool tools 已被转换为内置 tools。
dotnet watch
dotnet dev-certs
dotnet user-secrets
dotnet sql-cache
dotnet ef
升级到 .NET Core 2.1 时,请除去这些 tools 的项目引用。
Build Performance Improvements 构建性能优化
提高 .NET Core 构建的性能可能是该版本的最大焦点。 它在 .NET Core 2.1 中有了很大改进,特别是对于增量构建。这些改进适用于命令行上的 dotnet build
和 Visual Studio 中的构建。
与 .NET Core 2.0 相比,下图显示了我们所做的改进。我们专注于大型项目,正如您从图像中看到的那样。
(图:.NET Core 2.1增量式构建时性能改进。注意:图中2.1是指2.1.300 SDK版本。)
(注:这些测试数据来自 mikeharder/dotnet-cli-perf 项目。)
我们将长期运行的服务器添加到 .NET Core SDK 中,以提高常见开发操作的性能。这些服务器附加了进程运行时间超过单个 dotnet 构建调用。其中一些是迁移自 .NET Framework,另一些是全新的。
已添加以下 SDK 构建服务器:
- VBCSCompiler
- MSBuild worker processes
- Razor server
这些服务器的主要优点是它们跳过了在每个 dotnet 构建调用中 JIT 编译大块代码的需要。它们会在一段时间后自动终止。有关更好地控制这些构建服务器的更多信息,请参阅发行说明。
Runtime Performance Improvements 运行时性能优化
请参阅.NET Core 2.1中的性能改进一文,以深入了解该版本中的所有性能改进。
Networking Performance Improvements 网络性能优化
我们构建了一个名为 SocketHttpHandler 的全新从头开始的 HttpClientHandler 以提高网络性能。它是基于 .NET sockets 和 Span 的 HttpClient 的 C# 实现。
SocketsHttpHandler 现在是 HttpClient 的默认实现。 SocketsHttpHandler 最大的胜利就是性能。它比现有的实现快得多。它还消除了特定于平台的依赖关系,并支持跨操作系统的一致行为。
有关如何启用旧网络堆栈的说明,请参阅 .NET Core 2.1发行说明。
Span, Memory, and friends
我们正在进入一个使用 .NET 进行内存高效计算的新时代,引入 Span 及相关类型。今天,如果您想要传递 10,000 元素数组中的前 1000 个元素,则需要复制这 1000 个元素并将该副本传递给调用者。这种操作在时间和空间上都很昂贵。新的 Span 类型使您可以提供该阵列的虚拟视图,而无需时间或空间成本。 Span是一个结构体,这意味着您可以在不分配的情况下启用分析或其他计算的复杂流水线。出于这个原因,我们在 corefx 中广泛使用这种新类型。
Jared Parsons 在他的 Channel 9 video C# 7.2: Understanding Span 中给出了很好的介绍。 Stephen Toub 也有一篇文章介绍这些 C# – All About Span: Exploring a New .NET Mainstay。
在最简单的用例中,您可以将一个数组转换为Span,如下所示。
var arr = new byte[10];
Span<byte> bytes = arr; // Implicit cast from T[] to Span<T>
您可以Slice 一个 Span,如下所示。
// generating data for the example
int[] ints = new int[100];
for (var i = 0; i < ints.Length; i++)
{
ints[i] = i;
}
// creating span of array
Span<int> spanInts = ints;
// slicing the span, which creates another (subset) span
Span<int> slicedInts = spanInts.Slice(start: 42, length: 2);
// printing composition of the array and two spans
Console.WriteLine($"ints length: {ints.Length}");
Console.WriteLine($"spanInts length: {spanInts.Length}");
Console.WriteLine($"slicedInts length: {slicedInts.Length}");
Console.WriteLine("slicedInts contents");
for (var i = 0; i < slicedInts.Length; i++)
{
Console.WriteLine(slicedInts[i]);
}
// performing tests to validate the span has the expected contents
if (slicedInts[0] != 42) Console.WriteLine("error");
if (slicedInts[1] != 43) Console.WriteLine("error");
slicedInts[0] = 21300;
if (slicedInts[0] != ints[42]) Console.WriteLine("error");
// printing composition of subset span
Console.WriteLine("slicedInts contents");
for (var i = 0; i < slicedInts.Length; i++)
{
Console.WriteLine(slicedInts[i]);
}
这些代码产生如下输出:
ints length: 100
spanInts length: 100
slicedInts length: 2
slicedInts contents
42
43
slicedInts contents
21300
43
Brotli Compression Brotli 压缩
Brotli 是一种通用的无损压缩算法,压缩数据可与当前最好的通用压缩方法相媲美。速度与 deflate 相似,但提供更强力的压缩。Brotli 压缩数据格式的规范在 RFC 7932 中定义。大多数 Web 浏览器,主要 Web 服务器和一些 CDN(Content Delivery Networks)都支持 Brotli 编码。.NET Core Brotli 实现基于 Google 在 google/brotli 上提供的c代码。谢谢,谷歌!
Brotli 支持 已被添加到 .NET Core 2.1 中。操作可以使用基于流的 BrotliStream 或基于高性能跨度的 BrotliEncoder/BrotliDecoder 类来完成。你可以看到它在下面的例子中使用。
using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Threading.Tasks;
using static System.Console;
namespace BrotliApp
{
class Program
{
static readonly string s_URL = "https://raw.githubusercontent.com/dotnet/core/master/README.md";
static async Task Main(string[] args)
{
var client = new HttpClient();
var response = await client.GetAsync(s_URL,HttpCompletionOption.ResponseHeadersRead);
var stream = await response.Content.ReadAsStreamAsync();
WriteLine($"Request URL: {s_URL}");
WriteLine($"Initial content length: {response.Content.Headers.ContentLength}");
var compressedStream = CompressWithBrotli(stream);
WriteLine($"Compressed content length: {compressedStream.Length}");
var decompressedStream = DecompressWithBrotli(compressedStream);
WriteLine($"Decompressed content length: {decompressedStream.Length}");
WriteLine($"Compression ratio: {100 - (Decimal.Divide(compressedStream.Length, response.Content.Headers.ContentLength.Value)*100):N1}%");
WriteLine("First 10 lines of decompressed content");
WriteLine();
var reader = new StreamReader(decompressedStream);
for (var i = 0; i < 10; i++)
{
WriteLine(reader.ReadLine());
}
}
public static Stream CompressWithBrotli(Stream toCompress)
{
MemoryStream compressedStream = new MemoryStream();
using (BrotliStream compressionStream = new BrotliStream(compressedStream, CompressionMode.Compress, leaveOpen: true))
{
toCompress.CopyTo(compressionStream);
}
compressedStream.Position = 0;
return compressedStream;
}
public static Stream DecompressWithBrotli(Stream toDecompress)
{
MemoryStream decompressedStream = new MemoryStream();
using (BrotliStream decompressionStream = new BrotliStream(toDecompress, CompressionMode.Decompress, leaveOpen: true))
{
decompressionStream.CopyTo(decompressedStream);
}
decompressedStream.Position = 0;
return decompressedStream;
}
}
}
该代码产生以下输出:
Request URL: https://raw.githubusercontent.com/dotnet/core/master/README.md
Initial content length: 2244
Compressed content length: 727
Decompressed content length: 2244
Compression ratio: 67.6%
First 10 lines of decompressed content
# .NET Core Home
The dotnet/core repository is a good starting point for .NET Core.
The latest major release is [.NET Core 2.1](release-notes/2.1/2.1.0.md). The latest patch updates are listed in [.NET Core release notes](release-notes/README.md)
## Download the latest .NET Core SDK
* [.NET Core 2.1 SDK](release-notes/download-archives/2.1.0-download.md)
New Cryptography APIs 新的密码学API
.NET Core 密码学 API 已进行了以下增强:
- New SignedCms APIs — System.Security.Cryptography.Pkcs.SignedCms is now available in the System.Security.Cryptography.Pkcspackage. The .NET Core implementation is available to all .NET Core platforms and has parity with the class from .NET Framework. See: dotnet/corefx #14197.
- New X509Certificate.GetCertHash overload for SHA-2 — New overloads for X509Certificate.GetCertHash and X509Certificate.GetCertHashString accept a hash algorithm identifier to enable callers to get certificate thumbprint values using algorithms other than SHA-1. dotnet/corefx #16493.
- New Span-based cryptography APIs — Span-based APIs are available for hashing, HMAC, (cryptographic) random number generation, asymmetric signature generation, asymmetric signature processing, and RSA encryption.
- Rfc2898DeriveBytes performance improvements — The implementation of Rfc2898DeriveBytes (PBKDF2) is about 15% faster, based on using Span-based. Users who benchmarked an iteration count for an amount of server time may want to update iteration count accordingly.
- Added CryptographicOperations class — CryptographicOperations.FixedTimeEquals takes a fixed amount of time to return for any two inputs of the same length, making it suitable for use in cryptographic verification to avoid contributing to timing side-channel information. CryptographicOperations.ZeroMemory is a memory clearing routine that cannot be optimized away via a write-without-subsequent-read optimization.
- Added static RandomNumberGenerator.Fill — The static RandomNumberGenerator.Fill will fill a Span with random values using the system-preferred CSPRNG, and does not require the caller to manage the lifetime of an IDisposable resource.
- Added support for RFC 3161 cryptographic timestamps — New API to request, read, validate, and create TimestampToken values as defined by RFC 3161.
- Add Unix EnvelopedCms — The EnvelopedCms class has been added for Linux and macOS.
- Added ECDiffieHellman — Elliptic-Curve Diffie-Hellman (ECDH) is now available on .NET Core via the ECDiffieHellman class family with the same surface area as .NET Framework 4.7.
- Added RSA-OAEP-SHA2 and RSA-PSS to Unix platforms — Starting with .NET Core 2.1 the instance provided by RSA.Create() can always encrypt or decrypt with OAEP using a SHA-2 digest, as well as generate or validate signatures using RSA-PSS
Windows Compatibility Pack
将现有代码从 .NET Framework 移植到 .NET Core 时,可以使用 Windows Compatibility Pack。它提供了额外的 20,000 个API,与 .NET Core 中可用的 API 相比。这包括System.Drawing,EventLog,WMI,性能计数器和 Windows 服务。有关更多信息,请参阅Announcing the Windows Compatibility Pack for .NET Core。
以下示例演示使用 Windows Compatibility Pack 提供的 API 访问 Windows 注册表。
rivate static string GetLoggingPath()
{
// Verify the code is running on Windows.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
using (var key = Registry.CurrentUser.OpenSubKey(@"SoftwareFabrikamAssetManagement"))
{
if (key?.GetValue("LoggingDirectoryPath") is string configuredPath)
return configuredPath;
}
}
// This is either not running on Windows or no logging path was configured,
// so just use the path for non-roaming user-specific data files.
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
return Path.Combine(appDataPath, "Fabrikam", "AssetManagement", "Logging");
}
Tiered Compilation 分层编译
我们为运行时添加了一个新的令人兴奋的功能预览,称为分层编译。这是运行时更适应性地使用Just-In-Time(JIT)编译器以获得更好性能的一种方式。
JIT 编译器的基本挑战是编译时间是应用程序执行时间的一部分。生成更好的代码通常意味着花更多的时间来优化它。但是如果一段代码只执行一次或几次,编译器可能会花费更多时间优化它,而不是仅仅运行未优化版本。
通过分层编译,编译器首先尽可能快地生成代码,只需最少的优化(第一层)。然后,当它检测到某些方法执行了很多时,它会生成这些方法(第二层)的更优化版本,然后用它们代替。第二层编译是并行执行的,这消除了快速编译速度和生成最优代码之间的矛盾。这个模型可以更一般地称为自适应优化。
分层编译对长时间运行的应用程序(如Web服务器)也有好处。我们将在后续章节中详细介绍,但简短的版本是JIT可以生成比我们为 .NET Core 本身提供的预编译程序集更好的代码。这主要是由于fragile binary interface 问题。通过分层编译,JIT 可以使用它为 .NET Core 找到的预编译代码,然后为需要调用的方法编译更好的代码。我们已经看到这种情况对我们的性能实验室中的测试有很大的影响。
您可以通过设置环境变量来测试分层编译:
COMPlus_TieredCompilation="1"
您可以通过设置 TieredCompilation 属性为应用程序启用分层编译,如您在这个项目中所看到的。
Self-contained application publishing 自包含的应用程序发布
dotnet publish 现在发布带有服务运行时版本的self-contained applications。当您使用新 SDK 发布自包含应用程序时,您的应用程序将包含该 SDK 已知的最新服务运行时版本。当您升级到最新的 SDK 时,您将使用最新的 .NET Core 运行时版本进行发布。这适用于 .NET Core 1.0 运行时和更高版本。
自包含发布依赖于 NuGet.org 上的运行时版本。你不需要在你的机器上有服务运行时。
除非通过 RuntimeFrameworkVersion
属性指定了不同的版本,否则使用 .NET Core 2.0 SDK,自包含应用程序将与 .NET Core 2.0.0 Runtime 一起发布。有了这种新行为,您将不再需要设置此属性来为自包含应用程序选择更高的运行时版本。最简单的方法是始终使用最新的 SDK 进行安装和发布。
Docker
Docker Hub上 的 microsoft/dotnet 提供了用于 .NET Core 2.1 的 Docker 镜像。我们已经做了一些相对于 .NET Core 2.0 的更改。我们已经整合了用于 .NET Core和 ASP.NET Core 的 Docker Hub 存储库集合。我们将使用 microsoft/dotnet 作为我们为 .NET Core 2.1 及更高版本发布的唯一存储库。
我们向 .NET Core 镜像添加了一组环境变量,以便在任何 .NET Core 镜像层托管 ASP.NET Core站点,并在 SDK 容器镜像中启用 dotnet watch
而无需其他配置。
.NET Core Docker 示例 已移至 dotnet/dotnet-docker 库。 这些示例已针对 .NET Core 2.1 进行了更新。已添加新示例,包括通过 HTTPS 托管 ASP.NET Core Docker 镜像。
有关更多信息,请参见.NET Core 2.1 Docker 镜像更新 。
.NET Core 2.1 和兼容性
.NET Core 2.1 是一个高度兼容的版本。在没有安装 .NET Core 2.0 的情况下,.NET Core 2.0应用程序将在 .NET Core 2.1 上运行。这种前滚行为仅适用于次要版本, .NET Core 1.1 不会前滚到 2.0,.NET Core 2.0 也不会前滚到 3.0。
有关如何禁用次要版本前滚的说明,请参阅.NET Core 2.1发行说明。
如果您使用 .NET Core 2.1 预览版建立 .NET Core 2.1 应用程序或工具,则必须使用最终的 .NET Core 2.1 版本进行重建。预览版本不会前滚到最终版本。
Early Snap Installer Support 早期的 Snap 安装程序支持
我们一直致力于将 .NET Core 引入 Snap ,并准备好听取您的想法。 Snaps 以及其他一些技术,是我们认为很有趣的新兴应用程序安装和沙盒技术。Snap 安装适用于基于 Debian 的系统和其他发行版,例如 Fedora 正面临着我们正在努力解决的挑战。如果您想尝试一下,可以使用以下步骤。
.NET Core 2.1 运行时 和 SDK 的 Snap 可用:
sudo snap install dotnet-sdk --candidate --classic
sudo snap install dotnet-runtime-21 --candidate
留意未来的文章,探讨 Snaps 的内容。与此同时,我们很乐意听取您的反馈意见。
Closing 尾声
.NET Core 2.1 是该平台的一大进步。我们已经大幅改进了性能,添加了许多API,并增加了部署 tools 的新方法。我们还增加了对新的 Linux 发行版和另一种 CPU 类型 ARM32 的支持。此版本扩展了您可以使用 .NET Core 的地方,并使其在各处更加高效。
我们预计 .NET Core 2.1 将在本周晚些时候在 Azure App Service 中提供。
您可以看到我们使用.NET Core 2.1临时版本所取得的进展:RC1,Preview 2,Preview 1。再次感谢所有为此发布做出贡献的人。