适用于 .NET 8 的 SDK 和工具中的新增功能
本文介绍了适用于 .NET 8 的 SDK 和工具中的新增功能。
SDK 中 IsInRole 中的声明
本节包含下列子主题:
- 基于 CLI 的项目评估
- 终端生成输出
- 简化的输出路径
- “dotnet workload clean”命令
- “dotnet publish”和“dotnet pack”资产
- 模板引擎
- 源链接
- 源生成 SDK
基于 CLI 的项目评估
MSBuild 包含一项新功能,可更轻松地将数据从 MSBuild 合并到脚本或工具中。 以下新标志可用于 CLI 命令,例如用于获取数据以在 CI 管道或其他位置使用的 dotnet publish。
标记 | 说明 |
---|---|
--getProperty:<PROPERTYNAME> |
检索具有指定名称的 MSBuild 属性。 |
--getItem:<ITEMTYPE> |
检索指定类型的 MSBuild 项。 |
--getTargetResults:<TARGETNAME> |
检索运行指定目标的输出。 |
值将写入标准输出。 多个或复杂值将输出为 JSON,如以下示例所示。
>dotnet publish --getProperty:OutputPath
bin\Release\net8.0\
>dotnet publish -p PublishProfile=DefaultContainer --getProperty:GeneratedContainerDigest --getProperty:GeneratedContainerConfiguration
{
"Properties": {
"GeneratedContainerDigest": "sha256:ef880a503bbabcb84bbb6a1aa9b41b36dc1ba08352e7cd91c0993646675174c4",
"GeneratedContainerConfiguration": "{\u0022config\u0022:{\u0022ExposedPorts\u0022:{\u00228080/tcp\u0022:{}},\u0022Labels\u0022...}}"
}
}
>dotnet publish -p PublishProfile=DefaultContainer --getItem:ContainerImageTags
{
"Items": {
"ContainerImageTags": [
{
"Identity": "latest",
...
]
}
}
终端生成输出
dotnet build
具有可供生成更现代化的生成输出的新选项。 此终端记录器输出将错误与它们来自的项目分组,更好地区分多目标项目的不同目标框架,并提供有关生成所执行的操作的实时信息。 若要选择加入新输出,请使用 --tl
选项。 有关此选项的详细信息,请参阅 dotnet 生成选项。
简化的输出路径
.NET 8 引入了一个选项来简化生成输出的输出路径和文件夹结构。 以前,.NET 应用为不同的生成项目生成了一组深入而复杂的输出路径。 简化的新输出路径结构将所有生成输出收集到一个公共位置,这使得工具更容易预测。
有关详细信息,请参阅工件输出布局。
dotnet workload clean
命令
.NET 8 引入了一个新命令,用于清理可能通过多个 .NET SDK 或 Visual Studio 更新留下的工作负载包。 如果在管理工作负载时遇到问题,请考虑先使用 workload clean
安全地还原到已知状态,然后再重试。 此命令有两种模式:
dotnet workload clean
针对基于文件或基于 MSI 的工作负载运行工作负载垃圾回收,清理孤立包。 孤立包来自已卸载的 .NET SDK 版本或包,其中包的安装记录不再存在。
如果安装了 Visual Studio,该命令还会列出应使用 Visual Studio 手动清理的任何工作负载。
dotnet workload clean --all
此模式更积极,会在属于当前 SDK 工作负载安装类型的计算机上清理不是来自 Visual Studio 的每个包。 它还会删除正在运行的 .NET SDK 功能区段及更低版本的所有工作负载安装记录。
dotnet publish
和 dotnet pack
资产
由于 dotnet publish
和 dotnet pack
命令旨在生成生产资产,因此它们现在默认生成 Release
资产。
以下输出显示 dotnet build
和 dotnet publish
之间的不同行为,以及如何通过将 PublishRelease
属性设置为 false
来还原为发布 Debug
资产。
/app# dotnet new console
/app# dotnet build
app -> /app/bin/Debug/net8.0/app.dll
/app# dotnet publish
app -> /app/bin/Release/net8.0/app.dll
app -> /app/bin/Release/net8.0/publish/
/app# dotnet publish -p:PublishRelease=false
app -> /app/bin/Debug/net8.0/app.dll
app -> /app/bin/Debug/net8.0/publish/
有关详细信息,请参阅“dotnet pack”使用发布配置和“dotnet publish”使用发布配置。
dotnet restore
安全审核
从 .NET 8 开始,可以在还原依赖项包时选择对已知漏洞进行安全检查。 此审核会生成一份安全漏洞报告,其中包含受影响的包名称、漏洞的严重性,以及有关更多详细信息的公告链接。 运行 dotnet add
或 dotnet restore
时,将针对发现的任何漏洞显示 NU1901-NU1904 警告。 有关详细信息,请参阅审核安全漏洞。
模板引擎
模板引擎通过集成一些 NuGet 的安全相关功能,在 .NET 8 中提供了更安全的体验。 这些改进包括:
默认情况下,阻止从
http://
源下载包。 例如,以下命令将无法安装模板包,因为源 URL 不使用 HTTPS。dotnet new install console --add-source "http://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json"
使用
--force
标志可重写此限制。对于
dotnet new
、dotnet new install
和dotnet new update
,检查模板包中的已知漏洞。 如果发现漏洞并且想要继续,则必须使用--force
标志。对于
dotnet new
,请提供有关模板包所有者的信息。 所有权由 NuGet 门户验证,可视为可信特征。对于
dotnet search
和dotnet uninstall
,指示模板是否从“受信任”包安装,即它使用保留前缀。
源链接
源链接现在包含在 .NET SDK 中。 目标是通过将源链接捆绑到 SDK 中,而不是要求包具有单独的 <PackageReference>
,更多包将默认包含此信息。 此信息将改善开发人员的 IDE 体验。
注意
此更改的副作用是在生成的库和应用程序的 InformationalVersion
值中包含提交信息,即使是面向 .NET 7 或更早版本的库和应用程序。 有关详细信息,请参阅 .NET SDK 中包含的源链接。
源生成 SDK
Linux 分发生成(源生成)SDK 现在能够使用源生成运行时包生成自包含应用程序。 特定于分发的运行时包与源生成 SDK 捆绑在一起。 在独立部署期间,将引用此捆绑的运行时包,从而为用户启用该功能。
本机 AOT 支持
发布为本机 AOT 的选项最初是在 .NET 7 中引入的。 使用本机 AOT 发布应用会创建一个完全独立的应用版本,该版本不需要运行时,所有内容都包含在一个文件中。 .NET 8 为本机 AOT 发布带来了以下改进:
添加了对 macOS 上的 x64 和 Arm64 体系结构的支持。
Linux 上本机 AOT 应用的大小最多可缩小 50%。 下表显示了在 .NET 7 和 .NET 8 上使用包含整个 .NET 运行时的本机 AOT 发布的“Hello World”应用的大小:
操作系统 .NET 7 .NET 8 Linux x64(具有 -p:StripSymbols=true
)3.76 MB 1.84 MB Windows x64 2.85 MB 1.77 MB 允许指定优化首选项:大小或速度。 默认情况下,编译器选择以生成快速代码,同时请注意应用程序的大小。 但是,可以使用
<OptimizationPreference>
MSBuild 属性专门针对一个或另一个进行优化。 有关详细信息,请参阅优化 AOT 部署。
控制台应用模板
默认控制台应用模板现在包括对 AOT 开箱即用的支持。 若要创建为 AOT 编译配置的项目,只需运行 dotnet new console --aot
。 --aot
添加的项目配置有三种作用:
- 发布项目(例如,使用
dotnet publish
或 Visual Studio)时,使用本机 AOT 生成本机自包含可执行文件。 - 为剪裁、AOT 和单个文件启用兼容性分析器。 这些分析器会提醒你项目的潜在问题部分(如果有)。
- 启用 AOT 的调试时仿真,以便在不进行 AOT 编译的情况下调试项目时,获得与 AOT 类似的体验。 例如,如果在未为 AOT 添加批注的 NuGet 包中使用 System.Reflection.Emit(因此被兼容性分析器遗漏),则仿真意味着在进行 AOT 的情况下尝试发布项目时,不会有任何意外。
使用本机 AOT 面向类似 iOS 的平台
.NET 8 开始工作,为类似 iOS 的平台启用本机 AOT 支持。 你现在可在以下平台上使用本机 AOT 生成和运行 .NET iOS 和 .NET MAUI 应用程序:
ios
iossimulator
maccatalyst
tvos
tvossimulator
初步测试显示,对于使用本机 AOT 而不是 Mono 的 .NET iOS 应用,磁盘上的应用大小减少了约 35%。 .NET MAUI iOS 应用的磁盘应用大小最多可减少 50%。 此外,启动时间也更快。 .NET iOS 应用的启动时间快约 28%,与 Mono 相比,.NET MAUI iOS 应用的启动性能高约 50%。 .NET 8 支持是试验性的,且只是整个功能的第一步。 有关详细信息,请参阅 .NET MAUI 博客文章中的 .NET 8 性能提升。
本机 AOT 支持作为用于应用部署的一个选择加入功能提供;Mono 仍然是应用开发和部署的默认运行时。 若要在 iOS 设备上使用本机 AOT 生成和运行 .NET MAUI 应用程序,请使用 dotnet workload install maui
安装 .NET MAUI 工作负载,并使用 dotnet new maui -n HelloMaui
来创建应用。 然后,在项目文件中将 MSBuild 属性 PublishAot
设置为 true
。
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
设置了所需的属性并按下例所示运行 dotnet publish
时,将使用本机 AOT 部署应用。
dotnet publish -f net8.0-ios -c Release -r ios-arm64 /t:Run
限制
并非所有 iOS 功能都与本机 AOT 兼容。 同样,iOS 中常用的所有库并非都与 NativeAOT 兼容。 除了本机 AOT 部署的现有限制外,以下列表还显示了面向类似 iOS 的平台时的其他一些限制:
- 仅在应用部署 (
dotnet publish
) 期间启用本机 AOT。 - 只有 Mono 支持托管代码调试。
- 与 .NET MAUI 框架的兼容性受到限制。
针对 Android 应用的 AOT 编译
为了减小应用大小,面向 Android 的 .NET 和 .NET MAUI 应用在发布模式下构建时使用分析的预先 (AOT) 编译模式。 与常规 AOT 编译相比,分析的 AOT 编译所影响的方法更少。 .NET 8 引入了 <AndroidStripILAfterAOT>
属性,你可使用它进一步对 Android 应用进行 AOT 编译,从而更进一步减少应用大小。
<PropertyGroup>
<AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
</PropertyGroup>
默认情况下,将 AndroidStripILAfterAOT
设置为 true
会替代默认的 AndroidEnableProfiledAot
设置,从而允许剪裁已 AOT 编译的(几乎)所有方法。 还可通过将两个属性都显式设置为 true
来结合使用分析的 AOT 和 IL 条带化:
<PropertyGroup>
<AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>
交叉构建的 Windows 应用
在非 Windows 平台上构建针对 Windows 的应用时,生成的可执行文件现在使用任何指定的 Win32 资源(例如应用程序图标、清单、版本信息)进行更新。
以前,应用程序必须在 Windows 上构建才能有此类资源。 很多用户请求解决交叉构建支持方面的这一差距,因为它是影响基础结构复杂性和资源使用情况的一个重要痛点。
Linux 上的 .NET
Linux 的最低支持基线
适用于 .NET 8 的 Linux 最低支持基线已更新。 .NET 面向 Ubuntu 16.04 生成,适用于所有体系结构。 这对于定义 .NET 8 的最低 glibc
版本非常重要。 .NET 8 将无法在包含较旧 glibc 的发行版(例如 Ubuntu 14.04 或 Red Hat Enterprise Linux 7)上启动。
有关详细信息,请参阅 Red Hat Enterprise Linux 系列支持。
在 Linux 上生成你自己的 .NET
在以前的 .NET 版本中,可以从源生成 .NET,但需要从与发布相对应的 dotnet/installer 存储库提交创建“源 tarball”。 在 .NET 8 中,不再需要这样操作,你可以直接从 dotnet/dotnet 存储库在 Linux 上生成 .NET。 该存储库使用 dotnet/source-build 生成 .NET 运行时、工具和 SDK。 这是 Red Hat 和 Canonical 用于生成 .NET 的同一内部版本。
对于大多数人来说,在容器中生成是最简单的方法,因为 dotnet-buildtools/prereqs
容器映像包含所有必需的依赖项。 有关详细信息,请参阅生成说明。
NuGet 签名验证
从 .NET 8 开始,NuGet 默认在 Linux 上验证已签名的包。 NuGet 还会继续在 Windows 上验证已签名的包。
大多数用户不会注意到此验证。 但是,如果现有根证书捆绑包位于 /etc/pki/ca-trust/extracted/pem/objsign-ca-bundle.pem,则可能会看到信任失败并伴有警告 NU3042。
可以通过将环境变量 DOTNET_NUGET_SIGNATURE_VERIFICATION
设置为 false
来选择退出验证。
代码分析
.NET 8 包括几个新的代码分析器和修复程序,可帮助验证是否正确且高效地使用 .NET 库 API。 下表总结了新的分析器。
规则 ID | 类别 | 说明 |
---|---|---|
CA1856 | 性能 | 未在参数上正确应用 ConstantExpectedAttribute 属性时触发。 |
CA1857 | 性能 | 当参数使用 ConstantExpectedAttribute 添加批注但提供的参数不是常量时触发。 |
CA1858 | 性能 | 若要确定字符串是否以给定前缀开头,最好调用 String.StartsWith,而不是调用 String.IndexOf,然后将结果与零进行比较。 |
CA1859 | 性能 | 此规则建议尽可能将特定局部变量、字段、属性、方法参数和方法返回类型从接口或抽象类型升级到具体类型。 使用具体类型可生成更高质量的代码。 |
CA1860 | 性能 | 若要确定集合类型是否具有任何元素,最好使用 Length 、Count 或 IsEmpty ,而不是调用 Enumerable.Any。 |
CA1861 | 性能 | 重复调用时,不会重复使用作为参数传递的常量数组,这意味着每次都会创建一个新数组。 若要提高性能,请考虑将数组提取到静态只读字段。 |
CA1865-CA1867 | 性能 | 对于单字符串,char 重载的性能更好。 |
CA2021 | 可靠性 | Enumerable.Cast<TResult>(IEnumerable) 和 Enumerable.OfType<TResult>(IEnumerable) 需要兼容的类型才能正常运行。 泛型类型不支持扩大转换和用户定义的转换。 |
CA1510-CA1513 | 可维护性 | 在构造新的异常实例方面,引发帮助程序比 if 块更简单、更高效。 这四个分析器是为以下例外情况创建的:ArgumentNullException、ArgumentException、ArgumentOutOfRangeException 和 ObjectDisposedException。 |
诊断
C# 热重载支持修改泛型
从 .NET 8 开始,C# 热重载支持修改泛型类型和泛型方法。 使用 Visual Studio 调试控制台、桌面、移动或 WebAssembly 应用程序时,可以在 C# 代码或 Razor 页面中对泛型类和泛型方法应用更改。 有关详细信息,请参阅 Roslyn 支持的编辑完整列表。