本文介绍 .NET SDK 和 .NET 9 工具中的新功能。
单元测试
本部分介绍 .NET 9 中单元测试的更新:并行运行测试,以及终端记录器测试输出。
并行运行测试
在 .NET 9 中,dotnet test
与 MSBuild 更完全集成。 由于 MSBuild 支持并行生成,因此可以跨不同目标框架并行运行同一项目的测试。 默认情况下,MSBuild 将并行进程数限制为计算机上的处理器数。 还可以使用 -maxcpucount 开关设置自己的限制。 如果要选择退出并行度,请将 TestTfmsInParallel
MSBuild 属性设置为 false
。
终端记录器测试显示
现在,MSBuild 终端记录器中直接支持 dotnet test
的测试结果报告。 在测试运行时(显示正在运行的测试名称)和测试完成后(任何测试错误都会以更好的方式呈现),你都可以获得功能更齐全的测试报告。
有关终端记录器的详细信息,请参阅 dotnet 构建选项。
.NET 工具前滚行为
.NET 工具 是依赖于框架的应用程序,可以全局或本地安装,然后使用已安装的 .NET 运行时和 .NET SDK 进行运行。 这些工具(如所有 .NET 应用)面向特定主版本的 .NET。 默认情况下,应用不会在较新的 版本的 .NET 上运行。 工具作者可以通过设置 RollForward
MSBuild 属性,选择在较新版本的 .NET 运行时上运行其工具。 但是,并非所有工具都这样做。
dotnet tool install
的新选项使 用户 决定应如何运行 .NET 工具。 通过 dotnet tool install
安装工具或通过 dotnet tool run <toolname>
运行工具时,可以指定名为 --allow-roll-forward
的新标志。 此选项将工具配置为滚动前进模式 Major
。 如果匹配的 .NET 版本不可用,此模式允许该工具在较新的主版本 .NET 上运行。 此功能可帮助早期采用者使用 .NET 工具,而无需工具作者更改任何代码。
终端记录器
默认启用
从 .NET 9 开始,使用 MSBuild 的所有 .NET CLI 命令的默认体验是终端记录器,这是 .NET 8 中发布的增强日志记录体验。 此新输出使用新式终端的功能来提供如下功能:
- 可单击的链接
- MSBuild 任务的持续时间计时器
- 警告和错误消息的颜色编码
输出比现有的 MSBuild 控制台记录器更精简且可用。
新的记录器尝试自动检测是否可以使用它,但你也可以手动控制是否使用了终端记录器。 指定 --tl:off
命令行选项以禁用某个特定命令的终端记录器。 或者,若要更广泛地禁用终端记录器,请将 MSBUILDTERMINALLOGGER
环境变量设置为 off
。
默认情况下使用终端记录器的命令集为:
build
clean
msbuild
pack
publish
restore
test
可用性
终端日志记录器现在在构建结束时汇总故障和警告的总数。 它还显示包含换行符的错误。 (有关终端记录器的详细信息,请参阅 “dotnet build”选项,特别是 --tl
选项。
请考虑生成项目时发出警告的以下项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<Target Name="Error" BeforeTargets="Build">
<Warning Code="ECLIPSE001" Text="Black Hole Sun, won't you come
And wash away the rain
Black Hole Sun, won't you come
won't you come" />
</Target>
</Project>
在 .NET 8 SDK 上运行 dotnet build -tl
时,输出如以下段落所示。 多行警告的每一行都是一个单独的行,输出中带有完整错误消息前缀,难以阅读。 此外,最终的生成摘要表明有警告,但没有具体数量。 缺少的信息可能很难确定特定生成是否比以前的版本更好或更差。
$ dotnet build -tl
MSBuild version 17.8.5+b5265ef37 for .NET
Restore complete (0.5s)
multiline-error-example succeeded with warnings (0.2s) → bin\Debug\net8.0\multiline-error-example.dll
E:\Code\multiline-error-example.csproj(11,5): warning ECLIPSE001: Black Hole Sun, won't you come
E:\Code\multiline-error-example.csproj(11,5): warning ECLIPSE001: And wash away the rain
E:\Code\multiline-error-example.csproj(11,5): warning ECLIPSE001: Black Hole Sun, won't you come
E:\Code\multiline-error-example.csproj(11,5): warning ECLIPSE001: won't you come
Build succeeded with warnings in 0.9s
使用 .NET 9 SDK 生成同一项目时,输出如下所示:
> dotnet build -tl
Restore complete (0.4s)
You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
multiline-error-example succeeded with 3 warning(s) (0.2s) → bin\Debug\net8.0\multiline-error-example.dll
E:\Code\multiline-error-example.csproj(11,5): warning ECLIPSE001:
Black Hole Sun, won't you come
And wash away the rain
Black Hole Sun, won't you come
won't you come
Build succeeded with 3 warning(s) in 0.8s
警告消息行不再包含重复的项目和位置信息以避免显示混乱。 此外,构建摘要显示了构建期间产生了多少个警告(以及错误,如果有的话)。
如果对终端记录器有反馈,可以在 MSBuild 存储库中提供它。
用于大型存储库的 NuGet 依赖项解析速度更快
NuGet 依赖项解析程序已全面改革,以提高所有 <PackageReference>
项目的性能和可伸缩性。 默认情况下,新算法在不影响功能的情况下加快还原作速度,严格遵循核心依赖项解析规则。
如果遇到任何问题(例如还原失败或意外的包版本),则可以还原为旧解决程序。
MSBuild 脚本分析器 (“BuildChecks”)
.NET 9 引入了一项功能,可帮助防范生成脚本中的缺陷和回归。 若要运行生成检查,请将 /check
标志添加到调用 MSBuild 的任何命令。 例如,dotnet build myapp.sln /check
构建 myapp
解决方案并运行所有已配置的构建检查。
.NET 9 SDK 包括少量的初始检查,例如,BC0101 和 BC0102。 请参阅 BuildCheck 代码,获取完整列表。
检测到问题时,在包含问题的项目的生成输出中生成诊断。
分析器不匹配
许多用户以不同的节奏安装 .NET SDK 和 Visual Studio。 虽然这种灵活性是可取的,但它可能会导致需要在这两个环境之间互作的工具出现问题。 此类工具的一个示例是 Roslyn 分析器。 分析器作者必须为特定版本的 Roslyn 编写代码,但哪些版本可用以及给定构建中使用的是哪个版本,有时并不清楚。
.NET SDK 和 MSBuild 之间的这种版本不匹配称为残缺的 SDK。 处于此状态时,可能会看到如下所示的错误:
CSC:警告 CS9057:分析器程序集'.。\dotnet\sdk\8.0.200\Sdks\Microsoft.NET.Sdk.Razor\source-generators\Microsoft.CodeAnalysis.Razor.Compiler.SourceGenerators.dll“引用编译器的版本”4.9.0.0“,该版本比当前正在运行的版本”4.8.0.0“更新。
.NET 9 可以检测并自动调整此问题方案。 SDK 的 MSBuild 逻辑嵌入随附的 MSBuild 版本,该信息可用于检测 SDK 在具有不同版本的环境中运行时。 发生这种情况时,SDK 会插入名为 Microsoft.Net.Sdk.Compilers.Toolset 的支持包的隐式下载,以确保分析器体验一致。
工作负荷集
工作负荷集 是一项 SDK 功能,旨在让用户更好地控制其安装和更改这些工作负荷的节奏。 在以前的版本中,当各个工作负载的新版本发布到任一配置的 NuGet 源时,会定期更新工作负载。 现在,您的所有工作负载都保持为特定的单一版本,直到您进行明确的更新操作。
可以通过运行 dotnet workload --info
来查看 SDK 安装处于什么模式:
> dotnet workload --info
Workload version: 9.0.100-manifests.400dd185
Configured to use loose manifests when installing new manifests.
[aspire]
Installation Source: VS 17.10.35027.167, VS 17.11.35111.106
Manifest Version: 8.0.2/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.0.2\WorkloadManifest.json
Install Type: Msi
在此示例中,SDK 安装处于“清单”模式,其中更新在可用时安装。 若要选择加入新模式,请将 --version
选项添加到 dotnet workload install
或 dotnet workload update
命令。 还可以使用新的 dotnet workload config
命令显式控制操作模式。
> dotnet workload config --update-mode workload-set
Successfully updated workload install mode to use workload-set.
如果需要出于任何原因而重新更改,可以使用 manifests
而不是 workload-set
运行相同的命令。 还可以使用 dotnet workload config --update-mode
检查当前操作模式。
有关详细信息,请参阅 .NET SDK 工作负荷集。
工作负荷历史记录
.NET SDK 工作负载是 .NET MAUI 和 Blazor WebAssembly 不可或缺的一部分。 在默认配置下,您可以在 .NET 工具作者发布新版本时独立更新工作负载。 此外,通过 Visual Studio 完成的 .NET SDK 安装会安装一组并行版本。 如果不小心,给定 .NET SDK 安装的工作负荷安装状态可能会随时间而偏移,但还没有一种方法来可视化这种偏移。
为了解决此问题,.NET 9 向 .NET SDK 添加新的 dotnet workload history
命令。 dotnet workload history
输出当前 .NET SDK 安装的工作负荷安装和修改的历史记录表。 该表显示安装或修改的日期、运行的命令、已安装或修改的工作负载以及命令的相关版本。 此输出可帮助你了解工作负荷安装随时间推移的偏差,并帮助你做出有关将安装设置为哪些工作负荷版本的明智决策。 你可以将其视为工作负荷的 git reflog
。
> dotnet workload history
Id Date Command Workloads Global.json Version Workload Version
-----------------------------------------------------------------------------------------------------------------------------------------------
1 1/1/0001 12:00:00 AM +00:00 InitialState android, ios, maccatalyst, maui-windows 9.0.100-manifests.6d3c8f5d
2 9/4/2024 8:15:33 PM -05:00 install android, aspire, ios, maccatalyst, maui-windows 9.0.100-rc.1.24453.3
在此示例中,SDK 最初随 android
、ios
、maccatalyst
和 maui-windows
工作负荷一起安装。 然后,dotnet workload install aspire --version 9.0.100-rc.1.24453.3
命令用于安装 aspire
工作负荷,并切换到 工作负荷集模式。 若要返回到上一状态,可以使用历史记录表中第一列的 ID,例如,dotnet workload update --from-history 1
。
器皿
发布对不安全注册表的支持
SDK 的内置容器发布支持可以将映像发布到容器注册表。 在 .NET 9 之前,需要保护这些注册表,才能使 .NET SDK 正常工作,他们需要 HTTPS 支持和有效的证书。 容器引擎通常也可以配置为使用不安全的注册表,即未配置 TLS 或使用无效证书配置 TLS 的注册表。 这是一个有效的用例,但我们的工具不支持这种通信模式。
从 .NET 9 开始,SDK 可以与不安全的注册表通信。
要求(具体取决于环境):
- 配置 Docker CLI 以将注册表标记为不安全。
- 配置 Podman 以将注册表标记为不安全。
- 使用
DOTNET_CONTAINER_INSECURE_REGISTRIES
环境变量传递以分号分隔的注册表域列表,以被视为不安全。
环境变量命名
容器发布工具使用的环境变量用于控制注册表通信和安全的一些更精细的方面,现在以 DOTNET
为前缀,而不是 SDK
。 SDK
前缀将在短期内继续受支持。
代码分析
.NET 9 包含多个新的代码分析器和修复程序,以帮助验证你是否正确高效地使用 .NET 库 API。 下表汇总了新的分析器。
规则编号 | 类别 | 描述 |
---|---|---|
CA1514:避免冗余长度参数 | 可维护性 | 显式计算的长度参数可能容易出错,在切片到字符串或缓冲区末尾时不必要。 |
CA1515:考虑将公共类型变为内部 | 可维护性 | 可执行程序集内的类型应声明为 internal 。 |
CA1871:不要将可为 null 的结构传递给“ArgumentNullException.ThrowIfNull” | 性能 | 为了提高性能,最好检查 HasValue 属性并手动引发异常,而不是将可为 null 的结构传递给 ArgumentNullException.ThrowIfNull 。 |
CA1872:首选“Convert.ToHexString”和“Convert.ToHexStringLower”,而不是基于“BitConverter.ToString”的调用链 | 性能 | 将字节编码为十六进制字符串表示形式时,请使用 Convert.ToHexString 或 Convert.ToHexStringLower。 |
CA2022:使用 Stream.Read 避免不精确的读取 | 可靠性 | 对 Stream.Read 的调用可能返回的字节数可能少于请求的字节数,因此如果未检查返回值,则会导致代码不可靠。 |
CA2262:正确设置“MaxResponseHeadersLength” | 用法 | HttpClientHandler.MaxResponseHeadersLength 属性以 KB 而不是字节为单位进行度量。 |
CA2263:当类型为已知 时首选泛型重载 | 用法 | 在编译时已知类型的情况下,泛型重载优于接受类型 System.Type 参数的重载。 |
CA2264:不要将不可为 null 的值传递给“ArgumentNullException.ThrowIfNull” | 用法 | 某些结构(如不可为 null 的结构,Nullable<T> 除外)、“nameof()”表达式和“new”表达式已知永远不会为 null,因此永远不会引发 ArgumentNullException.ThrowIfNull 。 |
CA2265:不要将 Span<T> 与 null 或默认 进行比较 |
用法 | 将范围与 null 或 default 进行比较可能无法达到您的预期作用。 default 和 null 文本将隐式转换为 Span<T>.Empty。 删除冗余比较,或使用 IsEmpty 使代码更加明确。 |