.NET Core 3.0 的新增功能What's new in .NET Core 3.0

本文内容

本文介绍了 .NET Core 3.0 中的新增功能。最大的增强功能之一是对 Windows 桌面应用程序的支持(仅限 Windows)。通过使用 .NET Core 3.0 SDK Windows 桌面组件,可移植 Windows 窗体和 Windows Presentation Foundation (WPF) 应用程序。明确地说,只有在 Windows 上才支持和包含 Windows 桌面组件。有关详细信息,请参阅本文后面的 Windows 桌面部分。

.NET Core 3.0 添加了对 C#8.0 的支持。强烈建议使用 Visual Studio 2019 16.3Visual Studio for Mac 8.3Visual Studio Code 处理 C# 扩展 。

立即在 Windows、macOS 或 Linux 上下载并开始使用 .NET Core 3.0

有关版本的详细信息,请参阅 .NET Core 3.0 公告

Microsoft 认为 .NET Core RC1 可用于生产环境,且该软件完全受支持。如果使用的是预览版本,则必须转换为 RTM 版本才能继续获得支持。

.NET Core SDK Windows Installer.NET Core SDK Windows Installer

用于 Windows 的 MSI 安装程序已从 .NET Core 3.0 开始更改。SDK 安装程序现在将对 SDK 功能区段版本进行就地升级。功能区段在版本号的补丁部分中的百数组中定义。例如,3.0.1013.0.201 是两个不同功能区段中的版本,而 3.0.1013.0.199 则属于同一个功能区段。 并且,当安装 .NET Core SDK 3.0.101 时,将从计算机中删除 .NET Core SDK 3.0.100 (如果存在)。 当 .NET Core SDK 3.0.200 安装在同一台计算机上时,不会删除 .NET Core SDK 3.0.101

有关版本控制的详细信息,请参阅 .NET Core 的版本控制方式概述

C# 8.0C# 8.0

C# 8.0 也是该版本的一部分,它包含可为空引用类型功能、异步流和更多模式。有关 C# 8.0 功能的详细信息,请参阅 C# 8.0 中的新增功能

.NET Standard 2.1.NET Standard 2.1

尽管 .NET Core 3.0 支持 .NET Standard 2.1,默认的 dotnet new classlib 模板还是会生成一个仍然面向 .NET Standard 2.0 的项目 。若要面向 .NET Standard 2.1,请编辑项目文件并将 TargetFramework 属性更改为 netstandard2.1

  1. <Project Sdk="Microsoft.NET.Sdk">
  2. <PropertyGroup>
  3. <TargetFramework>netstandard2.1</TargetFramework>
  4. </PropertyGroup>
  5. </Project>

如果使用 Visual Studio,则需要 Visual Studio 2019,这是因为 Visual Studio 2017 不支持 .NET Standard 2.1 或 .NET Core 3.0 。

改进的 .NET Core 版本 APIImproved .NET Core Version APIs

从 .NET Core 3.0 开始,.NET Core 提供的版本 API 现在可以返回你预期的信息。例如:

  1. System.Console.WriteLine($"Environment.Version: {System.Environment.Version}");
  2. // Old result
  3. // Environment.Version: 4.0.30319.42000
  4. //
  5. // New result
  6. // Environment.Version: 3.0.0
  1. System.Console.WriteLine($"RuntimeInformation.FrameworkDescription: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}");
  2. // Old result
  3. // RuntimeInformation.FrameworkDescription: .NET Core 4.6.27415.71
  4. //
  5. // New result
  6. // RuntimeInformation.FrameworkDescription: .NET Core 3.0.0-preview4-27615-11

警告

重大变更。这在技术上是一个中断性变更,因为版本控制方案已发生变化。

.NET 平台相关内部函数.NET Platform-Dependent Intrinsics

已添加 API,允许访问某些性能导向的 CPU 指令,例如 SIMD 或位操作指令集 。这些指令有助于在某些情况下实现显著的性能改进,例如高效地并行处理数据。

在适当的情况下,.NET 库已开始使用这些指令来改进性能。

有关详细信息,请参阅 .NET Platform Dependent Intrinsics(.NET 平台相关内部函数)。

默认可执行文件Default executables

.NET Core 现在默认生成依赖于框架的可执行文件对于使用全局安装的 .NET Core 版本的应用程序而言,这是一种新行为。以前,仅独立部署会生成可执行文件。

dotnet builddotnet publish 期间,将创建一个与你使用的 SDK 的环境和平台相匹配的可执行文件。和其他本机可执行文件一样,可以使用这些可执行文件执行相同操作,例如:

  • 可以双击可执行文件。
  • 可以直接从命令提示符启用应用程序,如 Windows 上的 myapp.exe,以及 Linux 和 macOS 上的 ./myapp

单文件可执行文件Single-file executables

dotnet publish 命令支持将应用打包为特定于平台的单文件可执行文件。该可执行文件是自解压缩文件,包含运行应用所需的所有依赖项(包括本机依赖项)。首次运行应用时,应用程序将根据应用名称和生成标识符自解压缩到一个目录中。再次运行应用程序时,启动速度将变快。除非使用了新版本,否则应用程序无需再次进行自解压缩。

若要发布单文件可执行文件,请使用 dotnet publish 命令在项目或命令行中设置 PublishSingleFile

  1. <PropertyGroup>
  2. <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  3. <PublishSingleFile>true</PublishSingleFile>
  4. </PropertyGroup>

-或-

  1. dotnet publish -r win10-x64 /p:PublishSingleFile=true

有关单文件发布的详细信息,请参阅单文件捆绑程序设计文档

程序集链接Assembly linking

.NET core 3.0 SDK 随附了一种工具,可以通过分析 IL 并剪裁未使用的程序集来减小应用的大小。

自包含应用包括运行代码所需的所有内容,而无需在主计算机上安装 .NET。但是,很多时候应用只需要一小部分框架即可运行,并且可以删除其他未使用的库。

.NET Core 现在包含一个设置,将使用 IL 链接器工具扫描应用的 IL。此工具将检测哪些代码是必需的,然后剪裁未使用的库。此工具可以显著减少某些应用的部署大小。

要启用此工具,请使用项目中的 <PublishTrimmed> 设置并发布自包含应用:

  1. <PropertyGroup>
  2. <PublishTrimmed>true</PublishTrimmed>
  3. </PropertyGroup>
  1. dotnet publish -r <rid> -c Release

例如,包含的基本“hello world”新控制台项目模板在发布时命中大小约为 70 MB。通过使用 <PublishTrimmed>,其大小将减少到约 30 MB。

请务必考虑到使用反射或相关动态功能的应用程序或框架(包括 ASP.NET Core 和 WPF)通常会在剪裁时损坏。发生此损坏是因为链接器不知道此动态行为,并且不能确定反射需要哪些框架类型。可配置 IL 链接器工具以发现这种情况。

最重要的是,剪裁后务必对应用进行测试。

有关 IL 链接器工具的详细信息,请参阅文档,或访问 mono/linker 存储库。

分层编译Tiered compilation

.NET Core 3.0 中默认启用了分层编译 (TC)。此功能使运行时能够更适应地使用实时 (JIT) 编译器来获得更好的性能。

TC 的主要优势是使(重新)实时编译方法能够要么牺牲代码质量以更快地生成代码,要么以较慢的速度生成更高质量的代码。这有助于提高应用程序在从启动到稳定状态的各个执行阶段的性能。这与非 TC 方法完全不同,其中每种方法均以单一方式进行编译(与高质量层相同),这种方法偏向于稳定状态而不是启动性能。

若要启用快速 JIT(第 0 层实时编译的代码),请在项目文件中使用此设置:

  1. <PropertyGroup>
  2. <TieredCompilationQuickJit>true</TieredCompilationQuickJit>
  3. </PropertyGroup>

若要完全禁用 TC,请在项目文件中使用此设置:

  1. <TieredCompilation>false</TieredCompilation>

ReadyToRun 映像ReadyToRun images

可以通过将应用程序集编译为 ReadyToRun (R2R) 格式来改进.NET Core 应用程序的启动时间。R2R 是一种预先 (AOT) 编译形式。

R2R 二进制文件通过减少应用程序加载时实时 (JIT) 编译器需要执行的工作量来改进启动性能。二进制文件包含与 JIT 将生成的内容类似的本机代码。但是,R2R 二进制文件更大,因为它们包含中间语言 (IL) 代码(某些情况下仍需要此代码)和相同代码的本机版本。仅当发布面向特定运行时环境 (RID)(如 Linux x64 或 Windows x64)的自包含应用时 R2R 才可用。

若要将项目编译为 ReadyToRun,请执行以下操作:

  • 向项目中添加 <PublishReadyToRun> 设置
  1. <PropertyGroup>
  2. <PublishReadyToRun>true</PublishReadyToRun>
  3. </PropertyGroup>
  • 发布自包含应用。例如,此命令将创建适用于 Windows 64 位版本的自包含应用:
  1. dotnet publish -c Release -r win-x64 --self-contained true

跨平台/体系结构限制Cross platform/architecture restrictions

ReadyToRun 编译器当前不支持跨目标。必须在给定的目标上编译。例如,如果想要 Windows x64 R2R 映像,需要在该环境中运行发布命令。

跨目标的例外情况:

  • 可以使用 Windows x64 编译 Windows ARM32、ARM64 和 x86 映像。
  • 可以使用 Windows x86 编译 Windows ARM32 映像。
  • 可以使用 Linux x64 编译 Linux ARM32 和 ARM64 映像。

生成会复制依赖项Build copies dependencies

dotnet build 命令现在将应用程序的 NuGet 依赖项从 NuGet 缓存复制到生成输出文件夹。此前,依赖项仅作为 dotnet publish 的一部分复制。

有些操作,比如链接和 razor 页面发布仍需要发布。

本地工具Local tools

.NET Core 3.0 引入了本地工具。本地工具类似于全局工具,但与磁盘上的特定位置相关联。本地工具在全局范围内不可用,并作为 NuGet 包进行分发。

警告

如果尝试使用过 .NET Core 3.0 预览版 1 中的本地工具,例如运行 dotnet tool restoredotnet tool install,请删除本地工具缓存文件夹。否则,本地工具将无法在任何较新的版本上运行。此文件夹位于:

在 macOS、Linux 上:rm -r $HOME/.dotnet/toolResolverCache

在 Windows 上:rmdir /s %USERPROFILE%.dotnet\toolResolverCache

本地工具依赖于当前目录中名为 dotnet-tools.json 的清单文件。此清单文件定义在该文件夹和以下文件夹中可用的工具。你可以随代码一起分发清单文件,以确保使用代码的任何人都可以还原和使用相同的工具。

对于全局工具和本地工具,需要一个兼容的运行时版本。目前,NuGet.org 上的许多工具都面向 .NET Core Runtime 2.1。若要在全局范围或本地安装这些工具,仍需要安装 NET Core 2.1 运行时

主要版本前滚Major-version Roll Forward

.NET Core 3.0 引入了一项选择加入功能,该功能允许应用前滚到 .NET Core 最新的主要版本。此外,还添加了一项新设置来控制如何将前滚应用于应用。这可以通过以下方式配置:

  • 项目文件属性:RollForward
  • 运行时配置文件属性:rollForward
  • 环境变量:DOTNET_ROLL_FORWARD
  • 命令行参数:—roll-forward必须指定以下值之一。如果省略该设置,则默认值为“Minor” 。

  • LatestPatch前滚到最高补丁版本。这会禁用次要版本前滚。

  • Minor如果缺少所请求的次要版本,则前滚到最低的较高次要版本。如果存在所请求的次要版本,则使用 LatestPatch 策略。
  • Major如果缺少所请求的主要版本,则前滚到最低的较高主要版本和最低的次要版本。如果存在所请求的主要版本,则使用 Minor 策略。
  • LatestMinor即使存在所请求的次要版本,仍前滚到最高次要版本。适用于组件托管方案。
  • LatestMajor即使存在所请求的主要版本,仍前滚到最高主要版本和最高次要版本。适用于组件托管方案。
  • Disable不前滚。仅绑定到指定的版本。建议不要将此策略用于一般用途,因为它会禁用前滚到最新补丁的功能。该值仅建议用于测试。除“Disable”设置外,所有设置都将使用可用的最高补丁版本 。

Windows 桌面Windows desktop

.NET Core 3.0 支持使用 Windows Presentation Foundation (WPF) 和 Windows 窗体的 Windows 桌面应用程序。这些框架还支持通过 XAML 岛从 Windows UI XAML 库 (WinUI) 使用新式控件和 Fluent 样式。

Windows 桌面部件是 Windows .NET Core 3.0 SDK 的一部分。

可以使用以下 dotnet 命令创建新的 WPF 或 Windows 窗体应用:

  1. dotnet new wpf
  2. dotnet new winforms

Visual Studio 2019 添加了适用于 .NET Core 3.0 Windows 窗体和 WPF 的“新建项目” 模板。

有关如何移植现有 .NET Framework 应用程序的详细信息,请参阅移植 WPF 项目移植 Windows 窗体项目

可调用 COM 的组件 - Windows 桌面COM-callable components - Windows Desktop

在 Windows 上,现在可以创建可调用 COM 的托管组件。在将 .NET Core 与 COM 加载项模型结合使用,以及使用 .NET Framework 提供奇偶校验时,此功能至关重要。

与将 mscoree.dll 用作 COM 服务器的 .NET Framework 不同,.NET Core 将在生成 COM 组件时向 bin 目录添加本机启动程序 dll。

有关如何创建 COM 组件并使用它的示例,请参阅 COM 演示

MSIX 部署 - Windows 桌面MSIX Deployment - Windows Desktop

MSIX 是新的 Windows 应用程序包格式。可以使用它将 .NET Core 3.0 桌面应用程序部署到 Windows 10。

使用 Visual Studio 2019 中的 Windows 应用打包项目,可以创建包含独立式 .NET Core 应用的 MSIX 包。

.NET Core 项目文件必须在 <RuntimeIdentifiers> 属性中指定支持的运行时:

  1. <RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>

WinForms 高 DPIWinForms high DPI

.NET Core Windows 窗体应用程序可以使用 Application.SetHighDpiMode(HighDpiMode) 设置高 DPI 模式。SetHighDpiMode 方法可设置相应的高 DPI 模式,除非该设置已通过其他方式(例如使用 App.Manifest 或在 Application.Run 前面使用 P/Invoke)进行设置。

System.Windows.Forms.HighDpiMode 枚举表示的可能的 highDpiMode 值包括:

范围和索引Ranges and indices

System.Index 类型可用于编制索引。可从 int 创建一个从开头开始计数的索引,也可使用前缀 ^ 运算符 (C#) 创建一个从末尾开始计数的索引:

  1. Index i1 = 3; // number 3 from beginning
  2. Index i2 = ^4; // number 4 from end
  3. int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  4. Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

此外,还有 System.Range 类型,它包含两个 Index 值,一个用于开头一个用于结尾,可以使用 x..y 范围表达式 (C#) 进行编写。然后可以使用 Range 编制索引,以便生成一个切片:

  1. var slice = a[i1..i2]; // { 3, 4, 5 }

有关详细信息,请参阅范围和索引教程

异步流Async streams

IAsyncEnumerable<T> 类型是 IEnumerable<T> 的新异步版本。通过该语言,可通过 IAsyncEnumerable<T> 执行 await foreach 操作来使用其元素,并对其使用 yield return 操作来生成元素。

下面的示例演示如何生成和使用异步流。foreach 语句为异步语句,它本身使用 yield return 为调用方生成异步流。此模式(使用 yield return)是生成异步流的建议模型。

  1. async IAsyncEnumerable<int> GetBigResultsAsync()
  2. {
  3. await foreach (var result in GetResultsAsync())
  4. {
  5. if (result > 20) yield return result;
  6. }
  7. }

除了能够 await foreach,还可以创建异步迭代器,例如,一个返回 IAsyncEnumerable/IAsyncEnumerator 的迭代器,可以在其中进行 awaityield 操作。对于需要处理的对象,可以使用各种 BCL 类型(如 StreamTimer)实现的 IAsyncDisposable

有关详细信息,请参阅异步流教程

IEEE 浮点改进IEEE Floating-point improvements

正在更新浮点 API,以符合 IEEE 754-2008 修订这些更改旨在公开所有必需操作并确保这些操作在行为上符合 IEEE 规范。有关浮点改进的详细信息,请参阅 .NET Core 3.0 中的浮点分析和格式化改进博客文章。

分析和格式化修复包括:

  • 正确分析并舍入任何输入长度。
  • 正确分析并格式化负零。
  • 通过执行不区分大小写的检查并允许在前面使用可选的 +(如果适用),正确分析 InfinityNaN新的 System.Math API 包括:

  • BitIncrement(Double)BitDecrement(Double)相当于 nextUpnextDown IEEE 运算。它们将返回最小的浮点数,该数字大于或小于输入值(分别)。例如,Math.BitIncrement(0.0) 将返回 double.Epsilon

  • MaxMagnitude(Double, Double)MinMagnitude(Double, Double)相当于 maxNumMagminNumMag IEEE 运算,它们将(分别)返回大于或小于两个输入的量值的值。例如,Math.MaxMagnitude(2.0, -3.0) 将返回 -3.0

  • ILogB(Double)相当于返回整数值的 logB IEEE 运算,它将返回输入参数的整数对数(以 2 为底)。此方法实际上与 floor(log2(x)) 相同,但完成后出现最小舍入错误。

  • ScaleB(Double, Int32)相当于采用整数值的 scaleB IEEE 运算,它实际返回 x * pow(2, n),但完成后出现最小舍入错误。

  • Log2(Double)相当于返回(以 2 为底)对数的 log2 IEEE 运算。它会最小化舍入错误。

  • FusedMultiplyAdd(Double, Double, Double)相当于执行乘法加法混合的 fma IEEE 运算。也就是说,它以单个运算的形式执行 (x y) + z,从而最小化舍入错误。有关示例是返回 1e308FusedMultiplyAdd(1e308, 2.0, -1e308)。常规 (1e308 2.0) - 1e308 返回 double.PositiveInfinity

  • CopySign(Double, Double)相当于 copySign IEEE 运算,它返回 x 的值但带有符号 y

内置的快速 JSON 支持Fast built-in JSON support

.NET 用户在很大程度上依赖于 Json.NET 和其他常用的 JSON 库,它们仍是很好的选择。Json.NET 使用 .NET 字符串作为其基本数据类型,它实际上是 UTF-16。

新的内置 JSON 支持具有高性能、低分配的特点,并基于 Span<byte>已向 .NET Core 3.0 System.Text.Json 命名空间添加三个新的与 JSON 相关的主类型。这些类型不支持普通旧 CLR 对象 (POCO) 序列化和反序列化。

Utf8JsonReaderUtf8JsonReader

System.Text.Json.Utf8JsonReader 是面向 UTF-8 编码 JSON 文本的一个高性能、低分配的只进读取器,从 ReadOnlySpan<byte> 读取信息。Utf8JsonReader 是一种基本的低级类型,可用于生成自定义分析器和反序列化程序。使用新的 Utf8JsonReader 读取 JSON 有效负载要比使用 Json.NET 的读取器快 2 倍。在需要将 JSON 令牌实现为 (UTF-16) 字符串之前,它不会进行分配。

下面的示例展示了如何读取 Visual Studio Code 创建的 launch.json 文件:

  1. public static void PrintJson(ReadOnlySpan<byte> dataUtf8)
  2. {
  3. var json = new Utf8JsonReader(dataUtf8, isFinalBlock: true, state: default);
  4. while (json.Read())
  5. {
  6. JsonTokenType tokenType = json.TokenType;
  7. ReadOnlySpan<byte> valueSpan = json.ValueSpan;
  8. switch (tokenType)
  9. {
  10. case JsonTokenType.StartObject:
  11. case JsonTokenType.EndObject:
  12. break;
  13. case JsonTokenType.StartArray:
  14. case JsonTokenType.EndArray:
  15. break;
  16. case JsonTokenType.PropertyName:
  17. break;
  18. case JsonTokenType.String:
  19. Console.WriteLine($"STRING: {json.GetString()}");
  20. break;
  21. case JsonTokenType.Number:
  22. if (!json.TryGetInt32(out int valueInteger))
  23. {
  24. throw new FormatException();
  25. }
  26. break;
  27. case JsonTokenType.True:
  28. case JsonTokenType.False:
  29. Console.WriteLine($"BOOL: {json.GetBoolean()}");
  30. break;
  31. case JsonTokenType.Null:
  32. break;
  33. default:
  34. throw new ArgumentException();
  35. }
  36. }
  37. dataUtf8 = dataUtf8.Slice((int)json.BytesConsumed);
  38. JsonReaderState state = json.CurrentState;
  39. }
  1. // Calling code
  2. Console.WriteLine("Read with Utf8JsonReader");
  3. PrintJson(File.ReadAllBytes("launch.json").AsSpan());

Utf8JsonWriterUtf8JsonWriter

System.Text.Json.Utf8JsonWriter 提供了一种高性能、非缓存的只进方式,从常见 .NET 类型(例如,StringInt32DateTime)编写 UTF-8 编码的 JSON 文本。与阅读器一样,编写器是一种基本的低级类型,可用于生成自定义序列化程序。使用新的 Utf8JsonWriter 编写 JSON 有效负载比通过 Json.NET 使用编写器快 30-80%,且无需分配。

JsonDocumentJsonDocument

System.Text.Json.JsonDocument 是基于 Utf8JsonReader 构建的。JsonDocument 可分析 JSON 数据并生成只读文档对象模型 (DOM),可对模型进行查询,以支持随机访问和枚举。可以通过 JsonElement 类型(由 JsonDocument 公开为名为 RootElement 的属性)访问构成数据的 JSON 元素。JsonElement 包含 JSON 数组和对象枚举器,以及用于将 JSON 文本转换为常见 .NET 类型的 API。使用 JsonDocument 分析常规 JSON 有效负载并访问其所有成员比使用 Json.NET 快 2-3 倍,且为合理大小(即 < 1 MB)的数据所分配的量非常少。

下面是可用作起始点的 JsonDocumentJsonElement 的示例用法:

  1. public static void ReadJson(string jsonString)
  2. {
  3. using var document = JsonDocument.Parse(jsonString);
  4. var root = document.RootElement;
  5. var version = root.GetProperty("version").GetString();
  6. var configurations = root.GetProperty("configurations");
  7. Console.WriteLine($"Launch Version: {version}");
  8. foreach (var config in configurations.EnumerateArray())
  9. {
  10. var name = config.GetProperty("name").GetString();
  11. Console.WriteLine($"Config: {name}");
  12. }
  13. }

下面的 C# 8.0 示例展示了如何读取 Visual Studio Code 创建的 launch.json 文件:

  1. // Calling code
  2. Console.WriteLine("Read with JsonDocument");
  3. ReadJson(File.ReadAllText("launch.json"));

JsonSerializerJsonSerializer

System.Text.Json.JsonSerializerUtf8JsonReaderUtf8JsonWriter 的基础上生成,可在处理 JSON 文档和片段时提供快速的低内存序列化选项。

下面是一个将对象序列化为 JSON 的示例:

  1. var instance = new
  2. {
  3. FirstName = "John",
  4. LastName = "Smith",
  5. Age = 18
  6. };
  7. System.Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(instance));

下面是一个将 JSON 字符串反序列化为对象的示例。可以使用上一个示例生成的 JSON 字符串:

  1. public class JsonPerson
  2. {
  3. public string FirstName { get; set; }
  4. public string LastName { get; set; }
  5. public int Age { get; set; }
  6. public static JsonPerson Parse(string json) =>
  7. System.Text.Json.JsonSerializer.Deserialize<JsonPerson>(json);
  8. }

互操作性改进Interop improvements

.NET Core 3.0 改进了本机 API 互操作性。

类型:NativeLibraryType: NativeLibrary

System.Runtime.InteropServices.NativeLibrary 提供一个封装,用于加载本机库(使用与 .NET Core P/Invoke 相同的加载逻辑)并提供相关的帮助程序函数,例如 getSymbol有关代码示例,请参阅 DLLMap 演示

Windows 本机互操作Windows Native Interop

Windows 提供丰富的本机 API,包括平面 C API、COM 和 WinRT 的形式。.NET Core 支持 P/Invoke, .NET Core 3.0 则增加了 CoCreate COM APIActivate WinRT API 的功能。有关代码示例,请参阅 Excel 演示

HTTP/2 支持HTTP/2 support

System.Net.Http.HttpClient 类型支持 HTTP/2 协议。如果启用 HTTP/2,则将通过 TLS/ALPN 协商 HTTP 协议版本,并在服务器选择使用 HTTP/2 时使用。

默认协议将保留 HTTP/1.1,但可以在两种不同方法中启用 HTTP/2。首先,可以将 HTTP 请求消息设置为使用 HTTP/2:

  1. var client = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };
  2. // HTTP/1.1 request
  3. using (var response = await client.GetAsync("/"))
  4. Console.WriteLine(response.Content);
  5. // HTTP/2 request
  6. using (var request = new HttpRequestMessage(HttpMethod.Get, "/") { Version = new Version(2, 0) })
  7. using (var response = await client.SendAsync(request))
  8. Console.WriteLine(response.Content);

其次,可以更改 HttpClient 以默认使用 HTTP/2:

  1. var client = new HttpClient()
  2. {
  3. BaseAddress = new Uri("https://localhost:5001"),
  4. DefaultRequestVersion = new Version(2, 0)
  5. };
  6. // HTTP/2 is default
  7. using (var response = await client.GetAsync("/"))
  8. Console.WriteLine(response.Content);

很多时候,在你开发应用程序时要使用未加密的连接。如果你知道目标终结点将使用 HTTP/2,你可以为 HTTP/2 打开未加密的连接。可以通过将 DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2UNENCRYPTEDSUPPORT 环境变量设置为 1 或通过在应用上下文中启用它来将其打开:

  1. AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

Linux 上的 TLS 1.3 和 OpenSSL 1.1.1TLS 1.3 & OpenSSL 1.1.1 on Linux

.NET Core 现在可以在给定环境中使用 OpenSSL 1.1.1 中的 TLS 1.3 支持使用 TLS 1.3:

  • 通过减少客户端和服务器之间所需的往返次数,提高了连接时间。
  • 由于删除了各种过时和不安全的加密算法,提高了安全性。.NET Core 3.0 在 Linux 系统上使用 OpenSSL 1.1.1OpenSSL 1.1.0OpenSSL 1.0.2(如果可用)。OpenSSL 1.1.1 可用时,System.Net.Security.SslStreamSystem.Net.Http.HttpClient 类型都将使用 TLS 1.3(假定客户端和服务器都支持 TLS 1.3)。

重要

Windows 和 macOS 尚不支持 TLS 1.3 。当支持可用时,.NET Core 3.0 将在这些操作系统上支持 TLS 1.3 。

下面的 C# 8.0 示例演示在 Ubuntu 18.10 上 .NET Core 3.0 如何连接到 https://www.cloudflare.com

  1. using System;
  2. using System.Net.Security;
  3. using System.Net.Sockets;
  4. using System.Threading.Tasks;
  5. namespace whats_new
  6. {
  7. public static class TLS
  8. {
  9. public static async Task ConnectCloudFlare()
  10. {
  11. var targetHost = "www.cloudflare.com";
  12. using TcpClient tcpClient = new TcpClient();
  13. await tcpClient.ConnectAsync(targetHost, 443);
  14. using SslStream sslStream = new SslStream(tcpClient.GetStream());
  15. await sslStream.AuthenticateAsClientAsync(targetHost);
  16. await Console.Out.WriteLineAsync($"Connected to {targetHost} with {sslStream.SslProtocol}");
  17. }
  18. }
  19. }

加密密码Cryptography ciphers

.NET 3.0 增加了对 AES-GCMAES-CCM 密码的支持(分别使用 System.Security.Cryptography.AesGcmSystem.Security.Cryptography.AesCcm 实现)。这些算法都是用于关联数据的认证加密 (AEAD) 算法

下面的代码演示了如何使用 AesGcm 密码加密和解密随机数据。

  1. using System;
  2. using System.Linq;
  3. using System.Security.Cryptography;
  4. namespace whats_new
  5. {
  6. public static class Cipher
  7. {
  8. public static void Run()
  9. {
  10. // key should be: pre-known, derived, or transported via another channel, such as RSA encryption
  11. byte[] key = new byte[16];
  12. RandomNumberGenerator.Fill(key);
  13. byte[] nonce = new byte[12];
  14. RandomNumberGenerator.Fill(nonce);
  15. // normally this would be your data
  16. byte[] dataToEncrypt = new byte[1234];
  17. byte[] associatedData = new byte[333];
  18. RandomNumberGenerator.Fill(dataToEncrypt);
  19. RandomNumberGenerator.Fill(associatedData);
  20. // these will be filled during the encryption
  21. byte[] tag = new byte[16];
  22. byte[] ciphertext = new byte[dataToEncrypt.Length];
  23. using (AesGcm aesGcm = new AesGcm(key))
  24. {
  25. aesGcm.Encrypt(nonce, dataToEncrypt, ciphertext, tag, associatedData);
  26. }
  27. // tag, nonce, ciphertext, associatedData should be sent to the other part
  28. byte[] decryptedData = new byte[ciphertext.Length];
  29. using (AesGcm aesGcm = new AesGcm(key))
  30. {
  31. aesGcm.Decrypt(nonce, ciphertext, tag, decryptedData, associatedData);
  32. }
  33. // do something with the data
  34. // this should always print that data is the same
  35. Console.WriteLine($"AES-GCM: Decrypted data is {(dataToEncrypt.SequenceEqual(decryptedData) ? "the same as" : "different than")} original data.");
  36. }
  37. }
  38. }

加密密钥导入/导出Cryptographic Key Import/Export

.NET Core 3.0 支持从标准格式导入和导出非对称公钥和私钥。你不需要使用 X.509 证书。

所有密钥类型(例如 RSADSAECDsaECDiffieHellman)都支持以下格式:

  • 公钥

    • X.509 SubjectPublicKeyInfo
  • 私钥

    • PKCS#8 PrivateKeyInfo
    • PKCS#8 EncryptedPrivateKeyInfoRSA 密钥还支持:
  • 公钥

    • PKCS#1 RSAPublicKey
  • 私钥

    • PKCS#1 RSAPrivateKey导出方法生成 DER 编码的二进制数据,导入方法也是如此。如果密钥以文本友好的 PEM 格式存储,调用方需要在调用导入方法之前对内容进行 base64 解码。
  1. using System;
  2. using System.Security.Cryptography;
  3. namespace whats_new
  4. {
  5. public static class RSATest
  6. {
  7. public static void Run(string keyFile)
  8. {
  9. using var rsa = RSA.Create();
  10. byte[] keyBytes = System.IO.File.ReadAllBytes(keyFile);
  11. rsa.ImportRSAPrivateKey(keyBytes, out int bytesRead);
  12. Console.WriteLine($"Read {bytesRead} bytes, {keyBytes.Length - bytesRead} extra byte(s) in file.");
  13. RSAParameters rsaParameters = rsa.ExportParameters(true);
  14. Console.WriteLine(BitConverter.ToString(rsaParameters.D));
  15. }
  16. }
  17. }

可以使用 System.Security.Cryptography.Pkcs.Pkcs8PrivateKeyInfo 检查 PKCS#8 文件,使用 System.Security.Cryptography.Pkcs.Pkcs12Info 检查 PFX/PKCS#12 文件。可以使用 System.Security.Cryptography.Pkcs.Pkcs12Builder 操作 PFX/PKCS#12 文件。

适用于 Linux 的 SerialPortSerialPort for Linux

.NET Core 3.0 提供对 Linux 上 System.IO.Ports.SerialPort 的基本支持。

以前,.NET Core 只支持在 Windows 上使用 SerialPort

有关对 Linux 上串行端口有限支持的详细信息,请参阅 GitHub 问题 #33146

Docker 和 cgroup 内存限制Docker and cgroup memory Limits

在 Linux 上使用 Docker 运行 .NET Core 3.0 时,可更好地应对 cgroup 内存限制。运行具有内存限制的 Docker 容器(例如使用 docker run -m)会更改 .NET Core 的行为方式。

  • 默认垃圾回收器 (GC) 堆大小:最大为 20 MB 或容器内存限制的 75%。
  • 可以将显式大小设置为绝对数或 cgroup 限制的百分比。
  • 每个 GC 堆的最小保留段大小为 16 MB。此大小可减少在计算机上创建的堆数量。

垃圾回收堆大小减小Smaller Garbage Collection heap sizes

垃圾回收器的默认堆大小已减小,以使 .NET Core 使用更少的内存。此更改更符合具有现代处理器缓存大小的第 0 代分配预算。

垃圾回收大型页面支持Garbage Collection Large Page support

大型页面(也称为 Linux 上的巨型页面)是一项功能,其中操作系统能够建立大于本机页面大小(通常为 4K)的内存区域,以提高请求这些大型页面的应用程序的性能。

现在可以使用 GCLargePages 设置将垃圾回收器配置为一项选择加入功能,以选择在 Windows 上分配大型页面。

对 Raspberry Pi 的 GPIO 支持GPIO Support for Raspberry Pi

已向 NuGet 发布了两个可用于 GPIO 编程的包:

ARM64 Linux 支持ARM64 Linux support

.NET Core 3.0 增加了对 ARM64 for Linux 的支持。ARM64 的主要用例是当前的 IoT 场景。有关详细信息,请参阅 .NET Core ARM64 状态

ARM64 上适用于 .NET Core 的 Docker 映像可用于 Alpine、Debian 和 Ubuntu。

备注

ARM64 尚未提供 Windows 支持。