关于 migrate-dotnet8-to-dotnet9
该 Agent 技能指导将 .NET 8 项目或解决方案迁移到 .NET 9,供负责升级和维护 .NET 项目的开发者使用。它按项目技术栈检查兼容性、处理构建与行为变化,并更新部署基础设施。
主要功能
- 01评估项目构建、测试及技术栈
- 02更新目标框架和 Microsoft 包
- 03按技术栈排查编译问题
- 04审查 .NET 9 行为变化
- 05更新容器及部署配置
适用场景
- 01将 net8.0 项目升级到 net9.0
- 02处理更新 SDK 后出现的错误和警告
- 03适配 ASP.NET Core 9 或 EF Core 9
- 04更新 .NET 9 的 Dockerfile 和部署脚本
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dotnet/ skills --skill migrate-dotnet8-to-dotnet9安装后在 Claude Code 中输入/migrate-dotnet8-to-dotnet9确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/aspnet-core-dotnet8to9.mdcontainers-interop-dotnet8to9.mdcore-libraries-dotnet8to9.mdcryptography-dotnet8to9.mdcsharp-compiler-dotnet8to9.mddeployment-runtime-dotnet8to9.mdefcore-dotnet8to9.mdsdk-msbuild-dotnet8to9.mdserialization-networking-dotnet8to9.mdwinforms-wpf-dotnet8to9.md详细介绍
.NET 8 → .NET 9 迁移
将 .NET 8 项目或解决方案迁移到 .NET 9,系统地解决所有重大变更。最终项目将以 net9.0 为目标框架,能够干净地构建、通过测试,并涵盖 .NET 9 版本引入的所有行为变更、源代码不兼容变更和二进制不兼容变更。
适用场景
- 将
TargetFramework从net8.0升级到net9.0 - 更新 .NET 9 SDK 后解决构建错误或新增警告
- 适配 .NET 9 运行时、ASP.NET Core 9 或 EF Core 9 中的行为变更
- 替换
BinaryFormatter用法(该功能现在在运行时始终会引发异常) - 更新 .NET 9 的 CI/CD 管道、Dockerfile 或部署脚本
不适用场景
- 项目已面向
net9.0且能干净地构建——迁移已完成。如果目标是升级到net10.0,请将migrate-dotnet9-to-dotnet10技能作为下一步。 - 从 .NET 7 或更早版本升级——请先处理之前版本的重大变更
- 从 .NET Framework 迁移——这是另一项规模更大的工作
- 从 .NET 9 起步的新项目(无需迁移)
输入
| 输入 | 必需 | 描述 |
|---|---|---|
| 项目或解决方案路径 | 是 | 要迁移的入口文件:.csproj、.sln 或 .slnx |
| 构建命令 | 否 | 构建方式(例如 dotnet build、仓库构建脚本)。如果未提供,则自动检测 |
| 测试命令 | 否 | 运行测试的方式(例如 dotnet test)。如果未提供,则自动检测 |
| 项目类型提示 | 否 | 项目是否使用 ASP.NET Core、EF Core、WinForms、WPF、容器等。如果未提供,则根据 PackageReferences 和 SDK 属性自动检测 |
工作流
直接依据已加载的参考文档作答。 不要搜索文件系统或抓取网页来获取重大变更信息——参考文档包含权威详情。重点是识别适用的重大变更并提供具体修复方案。
提交策略: 在每个逻辑边界处提交——更新 TFM 后(步骤 2)、解决构建错误后(步骤 3)、处理行为变更后(步骤 4),以及更新基础设施后(步骤 5)。这样可以让每次提交都聚焦且便于审查。
步骤 1:评估项目
- 确定项目的构建和测试方式。查找构建脚本、
.sln/.slnx文件或单个.csproj文件。 - 运行
dotnet --version,确认已安装 .NET 9 SDK。如果未安装,请停止并告知用户。 - 检查以下内容,确定项目使用了哪些技术领域:
- SDK 属性:
Microsoft.NET.Sdk.Web→ ASP.NET Core;Microsoft.NET.Sdk.WindowsDesktop配合<UseWPF>或<UseWindowsForms>→ WPF/WinForms - PackageReferences:
Microsoft.EntityFrameworkCore.*→ EF Core;Microsoft.Extensions.Http→ HttpClientFactory - 存在 Dockerfile → 需关注容器相关变更
- 使用 P/Invoke 或本机互操作 → 需关注互操作变更
- 使用
BinaryFormatter→ 需进行序列化迁移 - 使用
System.Text.Json→ 需关注序列化变更 - X509Certificate 构造函数 → 需关注加密变更
- SDK 属性:
- 记录相关的参考文档(参见步骤 3 中的参考文档加载表)。
- 在当前
net8.0目标框架上执行一次干净构建(dotnet build --no-incremental或删除bin/obj),以建立干净的基线。记录所有已有警告。
步骤 2:更新目标框架
-
在每个
.csproj文件中(如果已集中配置,则在Directory.Build.props中),将:<TargetFramework>net8.0</TargetFramework>改为:
<TargetFramework>net9.0</TargetFramework>对于多目标项目,请将
net9.0添加到<TargetFrameworks>,或替换net8.0。 -
将所有
Microsoft.Extensions.*、Microsoft.AspNetCore.*、Microsoft.EntityFrameworkCore.*及其他 Microsoft 包引用更新到 9.0.x 版本。如果使用中央包管理(Directory.Packages.props),请在那里更新版本。 -
运行
dotnet restore。留意:- 版本要求:.NET 9 SDK 要求使用 Visual Studio 17.12+ 才能以
net9.0为目标(以net8.0及更早版本为目标则需使用 17.11)。 - 针对 .NET Standard 1.x 和 .NET 7 目标框架 的新警告——请考虑更新或移除过时的目标框架。
- 版本要求:.NET 9 SDK 要求使用 Visual Studio 17.12+ 才能以
-
执行干净构建。收集所有错误和新警告。这些问题将在步骤 3 中处理。
步骤 3:解决生成错误和源代码不兼容的更改
系统地处理编译错误和新警告。根据项目类型加载相应的参考文档:
| 如果项目使用…… | 加载参考文档 |
|---|---|
| 任何 .NET 9 项目 | references/csharp-compiler-dotnet8to9.md |
| 任何 .NET 9 项目 | references/core-libraries-dotnet8to9.md |
| 任何 .NET 9 项目 | references/sdk-msbuild-dotnet8to9.md |
| ASP.NET Core | references/aspnet-core-dotnet8to9.md |
| Entity Framework Core | references/efcore-dotnet8to9.md |
| Cryptography APIs | references/cryptography-dotnet8to9.md |
| System.Text.Json、HttpClient、networking | references/serialization-networking-dotnet8to9.md |
| Windows Forms 或 WPF | references/winforms-wpf-dotnet8to9.md |
| Docker containers、native interop | references/containers-interop-dotnet8to9.md |
| Runtime configuration、deployment | references/deployment-runtime-dotnet8to9.md |
需要检查的常见源代码不兼容更改:
-
paramsspan 重载解析 —String.Join、String.Concat、Path.Combine、Task.WhenAll等方法新增的params ReadOnlySpan<T>重载现在会优先匹配。在Expressionlambda 中调用这些方法的代码会报错(CS8640/CS9226)。请参阅references/core-libraries-dotnet8to9.md。 -
StringValues重载歧义 —params Span<T>功能会导致String.Concat、String.Join、Path.Combine等方法与StringValues隐式运算符发生歧义。通过显式转换参数来修复。请参阅references/core-libraries-dotnet8to9.md。 -
新增的过时警告(SYSLIB0054–SYSLIB0057):
SYSLIB0054:将Thread.VolatileRead/VolatileWrite替换为Volatile.Read/Volatile.WriteSYSLIB0057:将X509Certificate2/X509Certificate的二进制/文件构造函数替换为X509CertificateLoader方法- 另有
SYSLIB0055(ARM AdvSimd 有符号重载)和SYSLIB0056(使用哈希算法的 Assembly.LoadFrom)——请参阅references/core-libraries-dotnet8to9.md
-
C# 13 在 record struct 上使用
InlineArray— 现在禁止在record struct类型上使用[InlineArray]特性(CS9259)。请改用常规struct。请参阅references/csharp-compiler-dotnet8to9.md。 -
C# 13 迭代器安全上下文 — C# 13 中的迭代器现在会引入安全上下文。在迭代器内部、使用外层
unsafe类所继承的不安全代码的本地函数现在会报错。请为本地函数添加unsafe修饰符。请参阅references/csharp-compiler-dotnet8to9.md。 -
C# 13 集合表达式重载解析 — 空集合表达式(
[])不再通过 span 与非 span 进行重载决胜。现在会优先选择元素类型完全匹配的重载。请参阅references/csharp-compiler-dotnet8to9.md。 -
已移除
String.Trim(params ReadOnlySpan<char>)— 针对 .NET 9 预览版编译、且向Trim/TrimStart/TrimEnd传递ReadOnlySpan<char>的代码必须重新生成;此重载已在正式版中移除。请参阅references/core-libraries-dotnet8to9.md。 -
BinaryFormatter始终会抛出异常 — 如果项目使用BinaryFormatter,请停止并告知用户——这是一个重大决策。请参阅references/serialization-networking-dotnet8to9.md。 -
HttpListenerRequest.UserAgent可为 null — 此属性现在为string?。请添加 null 检查。请参阅references/serialization-networking-dotnet8to9.md。 -
Windows Forms 可空性注解更改 — 某些 WinForms API 参数已从可空改为不可空。请更新调用点。请参阅
references/winforms-wpf-dotnet8to9.md。 -
Windows Forms 安全分析器(WFO1000) — 新增的分析器会针对未显式配置序列化的属性报错。请参阅
references/winforms-wpf-dotnet8to9.md。
每批修复后都要再次生成。重复此过程,直至生成通过且无错误。
步骤 4:处理行为变更
行为变更不会导致生成错误,但可能会改变运行时行为。请检查每个适用项,并确定之前的行为是否被依赖。
影响较大的行为变更(优先检查):
-
浮点数到整数的转换现在采用饱和处理 — 在 x86/x64 上,从
float/double到整数类型的转换现在会采用饱和处理,而不再回绕。请参阅references/deployment-runtime-dotnet8to9.md。 -
EF Core:待处理模型变更异常 — 如果模型存在待处理变更,
Migrate()/MigrateAsync()现在会引发异常。请在任何HasData调用中搜索DateTime.Now、DateTime.UtcNow或Guid.NewGuid(),并将其替换为固定常量(例如,new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc))。请参阅references/efcore-dotnet8to9.md。 -
EF Core:显式事务异常 — 在用户事务中调用
Migrate()现在会引发异常。请参阅references/efcore-dotnet8to9.md。 -
HttpClientFactory 默认使用
SocketsHttpHandler— 将主要处理程序强制转换为HttpClientHandler的代码会导致InvalidCastException。请参阅references/serialization-networking-dotnet8to9.md。 -
HttpClientFactory 默认会对标头进行隐藏处理 —
Trace级别日志中的所有标头值现在都会被隐藏。请参阅references/serialization-networking-dotnet8to9.md。 -
环境变量的优先级高于 runtimeconfig.json — 环境变量中的运行时配置设置现在会覆盖
runtimeconfig.json。请参阅references/deployment-runtime-dotnet8to9.md。 -
ASP.NET Core 在开发环境中启用
ValidateOnBuild/ValidateScopes—HostBuilder现在默认会在开发环境中启用 DI 验证。请参阅references/aspnet-core-dotnet8to9.md。
需要检查的其他行为变更(可能导致运行时异常 ⚠️ 或细微的行为差异):
- ⚠️
FromKeyedServicesAttribute不再注入非键控服务作为回退 — 会引发InvalidOperationException - ⚠️ 容器映像不再安装 zlib — 依赖系统 zlib 的应用将无法运行
- ⚠️ Intel CET 现在默认启用 — 与 CET 不兼容的本机库可能导致进程终止
BigInteger的最大长度现在为(2^31) - 1位JsonDocument对 JSONnull的反序列化现在会返回非空的JsonDocument,其JsonValueKind为Null,而不是 C#nullSystem.Text.Json元数据读取器现在会对元数据属性名称取消转义ZipArchiveEntry名称/注释现在会遵循 UTF-8 标志IncrementingPollingCounter的初始回调现在是异步的InMemoryDirectoryInfo会将 rootDir 添加到文件路径前面RuntimeHelpers.GetSubArray返回的类型有所不同PictureBox会引发HttpRequestException,而不是WebExceptionStatusStrip使用不同的默认呈现器IMsoComponent支持现在需要显式启用SafeEvpPKeyHandle.DuplicateHandle会增加句柄的引用计数HttpClient指标现在始终报告server.port- HttpClient EventSource 事件和 IHttpClientFactory 日志中的 URI 查询字符串现在会被隐藏
dotnet watch与旧版框架的 Hot Reload 不兼容- WPF
GetXmlNamespaceMaps返回Hashtable,而不是String
步骤 5:更新基础设施
-
Dockerfile:更新基础映像。请注意,.NET 9 容器映像不再安装 zlib。如果应用依赖 zlib,请在 Dockerfile 中添加
RUN apt-get update && apt-get install -y zlib1g。# Before FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:8.0 # After FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:9.0 -
CI/CD 管道:更新 SDK 版本引用。如果使用
global.json,请更新:{ "sdk": { "version": "9.0.100", "rollForward": "latestFeature" } }检查
rollForward策略——如果设为"disable"或"latestPatch",升级后 SDK 可能无法正确解析。"latestFeature"(推荐)允许 SDK 自动切换到最新的 9.0.x 功能带。 -
Visual Studio 版本:.NET 9 SDK 需要 VS 17.12+ 才能以
net9.0为目标。VS 17.11 只能以net8.0及更早版本为目标。 -
终端记录器:现在,
dotnet build在交互式终端中默认使用终端记录器。解析 MSBuild 控制台输出的 CI 脚本可能需要使用--tl:off或MSBUILDTERMINALLOGGER=off。 -
dotnet workload输出:输出格式已更改。请更新解析工作负载命令输出的脚本。 -
.NET Monitor 映像:标签已简化为仅包含版本(这会影响引用特定标签的容器编排)。
步骤 6:验证
- 执行完整的干净构建:
dotnet build --no-incremental - 运行所有测试:
dotnet test - 如果应用已容器化,请构建并测试容器映像
- 对应用执行冒烟测试,特别注意:
- BinaryFormatter 的使用(将在运行时抛出异常)
- 浮点数转换为整数的行为
- EF Core 迁移的应用
- HttpClientFactory 处理程序的类型转换和日志记录
- 开发环境中的 DI 验证
- 运行时配置设置(环境变量优先级)
- 检查差异,确保没有引入意外的行为变更
参考文档
references/ 文件夹包含按技术领域整理的详细重大变更信息。仅加载与正在迁移的项目相关的参考资料:
| 参考文件 | 加载时机 |
|---|---|
references/csharp-compiler-dotnet8to9.md | 始终加载(C# 13 编译器重大变更——记录上的 InlineArray、迭代器安全上下文、集合表达式重载) |
references/core-libraries-dotnet8to9.md | 始终加载(适用于所有 .NET 9 项目) |
references/sdk-msbuild-dotnet8to9.md | 始终加载(SDK 和构建工具变更) |
references/aspnet-core-dotnet8to9.md | 项目使用 ASP.NET Core |
references/efcore-dotnet8to9.md | 项目使用 Entity Framework Core |
references/cryptography-dotnet8to9.md | 项目使用 System.Security.Cryptography 或 X.509 证书 |
references/serialization-networking-dotnet8to9.md | 项目使用 BinaryFormatter、System.Text.Json、HttpClient 或网络 API |
references/winforms-wpf-dotnet8to9.md | 项目使用 Windows Forms 或 WPF |
references/containers-interop-dotnet8to9.md | 项目使用 Docker 容器或本机互操作(P/Invoke) |
references/deployment-runtime-dotnet8to9.md | 项目使用运行时配置、部署,或包含浮点数转换为整数的操作 |