适用于 .NET 8 的 SDK 和工具中的新增功能

本文介绍了适用于 .NET 8 的 SDK 和工具中的新增功能。

SDK 中 IsInRole 中的声明

本节包含下列子主题:

基于 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 publishdotnet pack 资产

由于 dotnet publishdotnet pack 命令旨在生成生产资产,因此它们现在默认生成 Release 资产。

以下输出显示 dotnet builddotnet 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 adddotnet 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 newdotnet new installdotnet new update,检查模板包中的已知漏洞。 如果发现漏洞并且想要继续,则必须使用 --force 标志。

  • 对于 dotnet new,请提供有关模板包所有者的信息。 所有权由 NuGet 门户验证,可视为可信特征。

  • 对于 dotnet searchdotnet 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 性能 若要确定集合类型是否具有任何元素,最好使用 LengthCountIsEmpty,而不是调用 Enumerable.Any
CA1861 性能 重复调用时,不会重复使用作为参数传递的常量数组,这意味着每次都会创建一个新数组。 若要提高性能,请考虑将数组提取到静态只读字段。
CA1865-CA1867 性能 对于单字符串,char 重载的性能更好。
CA2021 可靠性 Enumerable.Cast<TResult>(IEnumerable)Enumerable.OfType<TResult>(IEnumerable) 需要兼容的类型才能正常运行。 泛型类型不支持扩大转换和用户定义的转换。
CA1510-CA1513 可维护性 在构造新的异常实例方面,引发帮助程序比 if 块更简单、更高效。 这四个分析器是为以下例外情况创建的:ArgumentNullExceptionArgumentExceptionArgumentOutOfRangeExceptionObjectDisposedException

诊断

C# 热重载支持修改泛型

从 .NET 8 开始,C# 热重载支持修改泛型类型和泛型方法。 使用 Visual Studio 调试控制台、桌面、移动或 WebAssembly 应用程序时,可以在 C# 代码或 Razor 页面中对泛型类和泛型方法应用更改。 有关详细信息,请参阅 Roslyn 支持的编辑完整列表

另请参阅