关于 migrate-dotnet9-to-dotnet10
帮助将 .NET 9 项目或解决方案迁移到 .NET 10,并系统处理破坏性变更。涵盖编译、运行时、框架及部署配置,并通过构建和测试验证结果。
主要功能
- 01评估项目与 SDK 状态
- 02更新目标框架和包
- 03处理编译层面的变更
- 04检查运行时行为变化
- 05更新 CI/CD 和部署文件
- 06验证构建与测试
适用场景
- 01将 net9.0 项目升级到 net10.0
- 02修复安装 .NET 10 SDK 后的错误
- 03适配 ASP.NET Core 或 EF Core 代码
- 04更新容器或 CI/CD 配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dotnet/ skills --skill migrate-dotnet9-to-dotnet10安装后在 Claude Code 中输入/migrate-dotnet9-to-dotnet10确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/aspnet-core-dotnet9to10.mdcontainers-interop-dotnet9to10.mdcore-libraries-dotnet9to10.mdcryptography-dotnet9to10.mdcsharp-compiler-dotnet9to10.mdefcore-dotnet9to10.mdextensions-hosting-dotnet9to10.mdsdk-msbuild-dotnet9to10.mdserialization-networking-dotnet9to10.mdwinforms-wpf-dotnet9to10.md详细介绍
.NET 9 → .NET 10 迁移
将 .NET 9 项目或解决方案迁移到 .NET 10,并系统地解决所有重大更改。最终项目将以 net10.0 为目标框架,能够顺利构建、通过测试,并处理 .NET 10 版本引入的所有行为更改、源代码不兼容更改和二进制不兼容更改。
适用场景
- 将
TargetFramework从net9.0升级到net10.0 - 更新 .NET 10 SDK 后解决构建错误或新警告
- 适配 .NET 10 运行时、ASP.NET Core 10 或 EF Core 10 的行为更改
- 更新 .NET 10 的 CI/CD 流水线、Dockerfile 或部署脚本
- 从社区提供的
System.Linq.Async包迁移到内置的System.Linq.AsyncEnumerable
不适用场景
- 项目已以
net10.0为目标框架且构建顺利 — 迁移已完成 - 从 .NET 8 或更早版本升级 — 请先使用
migrate-dotnet8-to-dotnet9技能升级到net9.0,然后再使用此技能完成从net9.0到net10.0的迁移 - 从 .NET Framework 迁移 — 这是另一项规模更大的工作
- 从零开始创建并以 .NET 10 为目标框架的项目(无需迁移)
输入
| 输入 | 必需 | 说明 |
|---|---|---|
| 项目或解决方案路径 | 是 | 要迁移的 .csproj、.sln 或 .slnx 入口点 |
| 构建命令 | 否 | 构建方式(例如 dotnet build、仓库构建脚本)。未提供时自动检测 |
| 测试命令 | 否 | 运行测试的方式(例如 dotnet test)。未提供时自动检测 |
| 项目类型提示 | 否 | 项目是否使用 ASP.NET Core、EF Core、WinForms、WPF、容器等。未提供时根据 PackageReferences 和 SDK 属性自动检测 |
工作流
直接依据已加载的参考文档作答。 请勿搜索文件系统或抓取网页来查找重大更改信息——参考文档包含权威详情。重点识别适用的重大更改并给出具体修复方案。**例外:**如果怀疑项目依赖项可能存在安全漏洞(CVE),请检查已发布的安全公告——参考文档可能未涵盖发布后的 CVE。
**提交策略:**在每个逻辑阶段完成后提交——更新 TFM 后(步骤 2)、解决构建错误后(步骤 3)、处理行为更改后(步骤 4)以及更新基础设施后(步骤 5)。这样每次提交内容集中,便于审查。
步骤 1:评估项目
- 确定项目的构建和测试方式。查找构建脚本、
.sln/.slnx文件或单独的.csproj文件。 - 运行
dotnet --version,确认已安装 .NET 10 SDK。若未安装,请停止并告知用户。 - 检查以下内容,确定项目使用的技术领域:
- SDK 属性:
Microsoft.NET.Sdk.Web→ ASP.NET Core;使用<UseWPF>或<UseWindowsForms>的Microsoft.NET.Sdk.WindowsDesktop→ WPF/WinForms - PackageReferences:
Microsoft.EntityFrameworkCore.*→ EF Core;Microsoft.Data.Sqlite→ Sqlite;Microsoft.Extensions.Hosting→ Generic Host / BackgroundService - 存在 Dockerfile → 适用容器更改
- 使用 P/Invoke 或本机互操作 → 适用互操作更改
- 引用
System.Linq.Async包 → 需要迁移到 AsyncEnumerable - 使用带多态功能的
System.Text.Json→ 适用序列化更改
- SDK 属性:
- 记录相关的参考文档(参见步骤 3 的参考文档加载表)。
- 在当前
net9.0目标框架上执行一次干净构建(运行dotnet build --no-incremental或删除bin/obj),建立干净的基线。记录所有已有警告。
步骤 2:更新目标框架
-
在每个
.csproj文件中(或集中配置时,在Directory.Build.props中),将:<TargetFramework>net9.0</TargetFramework>改为:
<TargetFramework>net10.0</TargetFramework>对于多目标项目,将
net10.0添加到<TargetFrameworks>,或替换net9.0。 -
将所有
Microsoft.Extensions.*、Microsoft.AspNetCore.*、Microsoft.EntityFrameworkCore.*及其他 Microsoft 包引用更新到 10.0.x 版本。如果使用中央包管理(Directory.Packages.props),请在那里更新版本。 -
运行
dotnet restore。注意以下情况:- NU1510:NuGet 修剪了直接引用 — 该包现在可能已包含在共享框架中。如果是这样,请移除显式的
<PackageReference>。 - 不带版本的 PackageReference 现在会引发错误 — 每个
<PackageReference>都必须指定Version(或使用 CPM)。 - NuGet 对传递包进行审核(
dotnet restore现在会审核传递依赖项)— 检查所有新增的漏洞警告。
- NU1510:NuGet 修剪了直接引用 — 该包现在可能已包含在共享框架中。如果是这样,请移除显式的
-
执行干净构建。收集所有错误和新增警告,并在步骤 3 中处理。
步骤 3:解决构建错误和源代码不兼容的更改
系统地处理编译错误和新增警告。根据项目类型加载相应的参考文档:
| 如果项目使用…… | 加载参考文档 |
|---|---|
| 任何 .NET 10 项目 | references/csharp-compiler-dotnet9to10.md |
| 任何 .NET 10 项目 | references/core-libraries-dotnet9to10.md |
| 任何 .NET 10 项目 | references/sdk-msbuild-dotnet9to10.md |
| ASP.NET Core | references/aspnet-core-dotnet9to10.md |
| Entity Framework Core | references/efcore-dotnet9to10.md |
| 加密 API | references/cryptography-dotnet9to10.md |
| Microsoft.Extensions.Hosting、BackgroundService、配置 | references/extensions-hosting-dotnet9to10.md |
| System.Text.Json、XmlSerializer、HttpClient、MailAddress、Uri | references/serialization-networking-dotnet9to10.md |
| Windows Forms 或 WPF | references/winforms-wpf-dotnet9to10.md |
| Docker 容器、单文件应用、原生互操作 | references/containers-interop-dotnet9to10.md |
需要检查的常见源代码不兼容更改:
-
System.Linq.Async冲突 — 移除System.Linq.Async包引用,或升级到 v7.0.0。如果该包是传递依赖,请添加<ExcludeAssets>compile</ExcludeAssets>。在需要的地方,将SelectAwait调用改为Select。 -
新增的弃用警告(SYSLIB0058–SYSLIB0062):
SYSLIB0058:将SslStream.KeyExchangeAlgorithm/CipherAlgorithm/HashAlgorithm替换为NegotiatedCipherSuite— 如果旧属性用于拒绝弱 TLS 密码套件,请使用新 API 保留等效的验证逻辑SYSLIB0059:将SystemEvents.EventsThreadShutdown替换为AppDomain.ProcessExitSYSLIB0060:将Rfc2898DeriveBytes构造函数替换为Rfc2898DeriveBytes.Pbkdf2SYSLIB0061:将采用IComparer<TSource>的Queryable.MaxBy/MinBy重载替换为采用IComparer<TKey>的重载SYSLIB0062:替换XsltSettings.EnableScript的用法
-
C# 14 属性访问器中的
field关键字 — 标识符field现在是属性get/set/init访问器中的上下文关键字。名为field的局部变量会导致 CS9272(错误)。引用时未加this.的名为field的类成员会导致 CS9258(警告)。可通过重命名(例如fieldValue)或使用@field转义来修复。请参阅references/csharp-compiler-dotnet9to10.md。 -
C# 14
extension上下文关键字 — 不允许将类型、别名或类型参数命名为extension。请重命名或使用@extension转义。 -
带 Span 参数的 C# 14 重载解析 — 数组上包含
.Contains()的表达式树现在可能会绑定到MemoryExtensions.Contains,而不是Enumerable.Contains。数组上的Enumerable.Reverse可能会解析为就地修改的Span扩展方法。可通过转换为IEnumerable<T>、使用.AsEnumerable()或显式静态调用来修复。完整详情请参阅references/csharp-compiler-dotnet9to10.md。 -
ASP.NET Core 弃用项(如适用):
WebHostBuilder、IWebHost、WebHost已弃用 — 迁移到Host.CreateDefaultBuilder或WebApplication.CreateBuilderIActionContextAccessor/ActionContextAccessor已弃用WithOpenApi扩展方法已弃用IncludeOpenAPIAnalyzers属性已弃用IPNetwork和ForwardedHeadersOptions.KnownNetworks已弃用- Razor 运行时编译已弃用
Microsoft.Extensions.ApiDescription.Client包已弃用Microsoft.OpenApiv2.x 的破坏性变更 —Microsoft.AspNetCore.OpenApi 10.0引入的Microsoft.OpenApiv2.x 重组了命名空间和模型。OpenApiString/OpenApiAny类型已移除(改用JsonNode),OpenApiSecurityScheme.Reference已替换为OpenApiSecuritySchemeReference,OpenAPI 模型对象上的集合可能为 null,且OpenApiSchema.Nullable已移除。迁移模式请参阅references/aspnet-core-dotnet9to10.md。
-
SDK 变更:
dotnet new sln现在默认使用 SLNX 格式 — 如需旧格式,请使用--format sln- 文件级指令中不允许使用双引号
- .NET SDK 已移除
dnx.ps1 dotnet restore不再支持project.json
-
EF Core 源代码变更(如适用)— 参阅
references/efcore-dotnet9to10.md,了解以下内容:ExecuteUpdateAsync现在接受常规 Lambda(必须重写表达式树构造代码)IDiscriminatorPropertySetConvention签名已变更IRelationalCommandDiagnosticsLogger方法新增了logCommandText参数
-
WinForms/WPF 源代码变更(如适用):
- 同时引用 WPF 和 WinForms 的应用程序必须消除
MenuItem和ContextMenu类型的歧义 HtmlElement.InsertAdjacentElement中的参数已重命名- WPF 不允许使用空的
ColumnDefinitions和RowDefinitions
- 同时引用 WPF 和 WinForms 的应用程序必须消除
-
加密源代码变更(如适用):
MLDsa和SlhDsa成员的名称已从SecretKey改为PrivateKey(例如,ExportMLDsaSecretKey→ExportMLDsaPrivateKey,SecretKeySizeInBytes→PrivateKeySizeInBytes)Rfc2898DeriveBytes构造函数已弃用(SYSLIB0060)— 替换为静态方法Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, hashAlgorithm, outputLength)CoseSigner.Key现在可以为 null — 使用前请检查是否为 nullX509Certificate.GetKeyAlgorithmParameters()和PublicKey.EncodedParameters可能返回 null- 环境变量已从
CLR_OPENSSL_VERSION_OVERRIDE重命名为DOTNET_OPENSSL_VERSION_OVERRIDE
每批修复后都重新构建。重复此过程,直到构建通过。
步骤 4:处理行为变更
行为变更不会导致生成错误,但可能改变运行时行为。请逐项检查所有适用项,并确定是否依赖过之前的行为。
高影响行为变更(优先检查):
-
已移除 SIGTERM 信号处理 — .NET 运行时不再注册默认的 SIGTERM 处理程序。如果你依赖在收到 SIGTERM 时触发
AppDomain.ProcessExit或AssemblyLoadContext.Unloading:- ASP.NET Core 和 Generic Host 应用不受影响(它们会注册自己的处理程序)
- 未使用 Generic Host 的控制台应用和容器化应用必须显式注册
PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => Environment.Exit(0))
-
BackgroundService.ExecuteAsync 完全在后台线程上运行 — 首次
await之前的同步部分不再阻塞启动。如果启动顺序很重要,请将相关代码移至StartAsync或构造函数中,或者实现IHostedLifecycleService。 -
现在会保留配置中的 null 值 — JSON
null值不再转换为空字符串。使用非默认值初始化的属性会被null覆盖。请检查配置绑定代码。 -
Microsoft.Data.Sqlite 的 DateTimeOffset 变更(均为高影响):
GetDateTimeOffset在值不带偏移量时现在假定时区为 UTC(此前假定为本地时区)- 将
DateTimeOffset写入 REAL 列时,现在会先转换为 UTC GetDateTime在值带偏移量时,现在返回DateTimeKind.Utc的 UTC 时间- 缓解方法:将
AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true)用作临时解决办法
-
EF Core 参数化集合 — 集合上的
.Contains()现在使用多个标量参数,而不是 JSON/OPENJSON。可能会影响大型集合的查询性能。缓解方法:使用UseParameterizedCollectionMode(ParameterTranslationMode.Parameter)恢复原行为。 -
Azure SQL 上 EF Core 的 JSON 数据类型 — Azure SQL 且兼容级别 ≥170 时,现在使用
json数据类型,而不是nvarchar(max)。系统会生成迁移来更改现有列。缓解方法:将兼容级别设为 160,或显式使用HasColumnType("nvarchar(max)")。 -
System.Text.Json 属性名称冲突验证 — 属性与元数据名称(
$type、$id、$ref)冲突的多态类型现在会引发InvalidOperationException。请为冲突的属性添加[JsonIgnore]。
需要检查的其他行为变更:
BufferedStream.WriteByte不再隐式刷新 — 如有需要,请显式调用Flush()- 默认跟踪上下文传播器已更新为 W3C 标准
DriveInfo.DriveFormat返回实际的 Linux 文件系统类型名称- LDAP
DirectoryControl解析更加严格 - 默认 .NET 容器映像已从 Debian 切换为 Ubuntu(不再提供 Debian 映像)
- 默认情况下,单文件应用不再在可执行文件目录中查找本机库
DllImportSearchPath.AssemblyDirectory只会搜索程序集目录MailAddress会验证是否存在连续句点- 浏览器 HTTP 客户端默认启用流式 HTTP 响应
- 已移除
Uri长度限制 — 如果曾使用Uri拒绝不可信来源的超长输入,请添加显式长度验证 - 对已知 API 端点禁用 Cookie 登录重定向(ASP.NET Core)
XmlSerializer不再忽略带有[Obsolete]的属性 — 请检查过时属性中是否包含敏感数据,并添加[XmlIgnore]以防止意外暴露数据dotnet restore会审计传递依赖包dotnet watch改为向 stderr 而不是 stdout 写入日志dotnetCLI 命令会将与命令无关的数据记录到 stderr- 各类 NuGet 行为变更(请参阅
references/sdk-msbuild-dotnet9to10.md) StatusStrip默认使用 System RenderMode(WinForms)- 已修复
TreeView复选框图像截断问题(WinForms) - 错误使用
DynamicResource会导致崩溃(WPF)
步骤 5:更新基础设施
-
Dockerfiles:更新基础镜像。默认标签现在使用 Ubuntu,而不是 Debian。对于 .NET 10,不再提供 Debian 镜像。
# Before FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:9.0 # After FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:10.0 -
CI/CD 管道:更新 SDK 版本引用。如果使用
global.json,请更新:{ "sdk": { "version": "10.0.100" } } -
环境变量已重命名:
DOTNET_OPENSSL_VERSION_OVERRIDE替代旧名称DOTNET_ICU_VERSION_OVERRIDE替代旧名称NUGET_ENABLE_ENHANCED_HTTP_RETRY已移除
-
OpenSSL 要求:现在 Unix 上需要 OpenSSL 1.1.1 或更高版本。macOS 上不再支持 OpenSSL 加密原语。
-
解决方案文件格式:如果脚本中使用了
dotnet new sln,请注意它现在会生成 SLNX 格式。如果需要旧格式,请传入--format sln。
步骤 6:验证
- 执行完整的干净构建:
dotnet build --no-incremental - 运行所有测试:
dotnet test - 如果应用已容器化,请构建并测试容器镜像
- 对应用进行冒烟测试,特别关注:
- 信号处理/正常关闭行为
- 后台服务启动顺序
- 对 null 值的配置绑定
- 使用 Sqlite 处理日期/时间
- 多态类型的 JSON 序列化
- 对集合使用
.Contains()的 EF Core 查询
- 安全审查——确认迁移没有削弱安全控制:
SslStreamAPI 迁移后,TLS 密码套件验证逻辑仍然保留(SYSLIB0058)- 排除包含敏感数据的过时属性,避免其被序列化(
[XmlIgnore]、[JsonIgnore]) - 如果曾将
Uri用作长度限制,输入验证仍会拒绝超长 URI - 异常处理程序在返回
true前会发出与安全相关的遥测数据(身份验证失败、访问违规) - 连接字符串设置了明确的
Application Name,且不会泄露版本信息 - 处理
dotnet restore漏洞审计发现的问题,而不是将其忽略
- 检查差异,确保没有引入意外的行为变更
参考文档
references/ 文件夹包含按技术领域整理的详细重大变更信息。只加载与待迁移项目相关的参考资料:
| 参考文件 | 加载时机 |
|---|---|
references/csharp-compiler-dotnet9to10.md | 始终加载(C# 14 编译器重大变更——field 关键字、extension 关键字、span 重载) |
references/core-libraries-dotnet9to10.md | 始终加载(适用于所有 .NET 10 项目) |
references/sdk-msbuild-dotnet9to10.md | 始终加载(SDK 和构建工具变更) |
references/aspnet-core-dotnet9to10.md | 项目使用 ASP.NET Core |
references/efcore-dotnet9to10.md | 项目使用 Entity Framework Core 或 Microsoft.Data.Sqlite |
references/cryptography-dotnet9to10.md | 项目使用 System.Security.Cryptography 或 X.509 证书 |
references/extensions-hosting-dotnet9to10.md | 项目使用 Generic Host、BackgroundService 或 Microsoft.Extensions.Configuration |
references/serialization-networking-dotnet9to10.md | 项目使用 System.Text.Json、XmlSerializer、HttpClient 或网络 API |
references/winforms-wpf-dotnet9to10.md | 项目使用 Windows Forms 或 WPF |
references/containers-interop-dotnet9to10.md | 项目使用 Docker 容器、单文件发布或本机互操作(P/Invoke) |