.NET 10 到 .NET 11 迁移实战指南:基于 migrate-dotnet10-to-dotnet11 技能的系统化升级路径
【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills
导读:本文围绕当前仓库中
migrate-dotnet10-to-dotnet11技能文档展开,系统梳理将 .NET 10 项目迁移至 .NET 11(net11.0)的完整工作流:从环境评估、Target Framework 更新,到 C# 15 编译器源码级破坏性变更、运行时/核心库行为变更、EF Core 11 与 ASP.NET Core 11 专项适配,再到 Docker 与 CI/CD 基础设施升级与最终验证。读完本文,你将掌握一套可复用的迁移清单与每个破坏性变更的具体修复方案,能够直接指导真实仓库完成迁移并保证构建与测试通过。
注意:.NET 11 目前处于预览阶段,本文所述破坏性变更覆盖截至Preview 3的内容,后续预览版本可能引入更多变更。
技能定位:这是一份「迁移技能」而非「新建项目指南」
在 SKILL.md 的 frontmatter 中,该技能被明确标注为MIGRATION skill:
适用场景(When to Use):
- 将
TargetFramework从net10.0升级为net11.0; - 更新 .NET 11 SDK 后解决构建错误或新出现的警告;
- 适配 .NET 11 运行时、ASP.NET Core 11、EF Core 11 的行为变更;
- 为 .NET 11 更新 CI/CD 流水线、Dockerfile 或部署脚本;
- 修复 SDK 升级后 C# 15 编译器引入的破坏性变更。
- 将
不适用场景(When Not to Use):
- 项目已目标
net11.0且构建干净(迁移已完成); - 从 .NET 9 或更早版本升级(需先处理 9→10 的破坏性变更);
- 从 .NET Framework 迁移(属于另一项更大的工程);
- 直接以 .NET 11 起步的新项目(无需迁移)。
- 项目已目标
核心原则:迁移信息以技能自带的 reference 文档为权威来源(
do not fetch web pages or other external sources),并通过「按逻辑边界提交」的提交策略(更新 TFM 后、修复构建错误后、处理行为变更后、更新基础设施后各提交一次)保证每个提交聚焦且可评审。
输入参数
| 输入 | 是否必需 | 说明 |
|---|---|---|
| 项目或解决方案路径 | 是 | 待迁移的.csproj、.sln或.slnx入口点 |
| 构建命令 | 否 | 构建方式(如dotnet build或仓库构建脚本),未提供时自动检测 |
| 测试命令 | 否 | 测试运行方式(如dotnet test),未提供时自动检测 |
| 项目类型提示 | 否 | 是否使用 ASP.NET Core、EF Core、Cosmos DB 等,未提供时从 PackageReferences 与 SDK 属性自动检测 |
六步迁移工作流
Step 1:项目评估(Assess the project)
在动手修改任何文件之前,先建立清晰的基线:
- 识别构建与测试方式:查找构建脚本、
.sln/.slnx文件或单个.csproj。 - 确认 SDK 版本:运行
dotnet --version确认已安装 .NET 11 SDK;若未安装,立即停止并告知用户。 - 判定技术领域,通过以下线索快速定位可能受影响的模块:
- SDK 属性:
Microsoft.NET.Sdk.Web→ ASP.NET Core;Microsoft.NET.Sdk.WindowsDesktop且含<UseWPF>或<UseWindowsForms>→ WPF/WinForms; - PackageReferences:
Microsoft.EntityFrameworkCore.*→ EF Core;Microsoft.EntityFrameworkCore.Cosmos→ Cosmos DB provider; - Dockerfile 存在→ 容器镜像变更相关;
- 加密 API 使用→ macOS 上 DSA 受影响、AIA 证书下载变更相关;
- 压缩 API 使用→ DeflateStream/GZipStream/ZipArchive 变更相关;
- TAR API 使用→ 头部校验和验证与 HardLink 条目变更相关;
NamedPipeClientStream搭配SafePipeHandle→ SYSLIB0063 构造函数弃用相关;BackgroundService使用→ 未处理异常将终止宿主;- 直接使用
Microsoft.OpenApi→ ASP.NET Core OpenAPI v3 API 破坏性变更; - EF Core SQL Server 搭配 Entra ID 认证→ SqlClient 7.0 认证依赖变更;
- Unix 上 NativeAOT 原生库→ 输出文件名
lib前缀变化。
- SDK 属性:
- 记录相关 reference 文档(加载对照表见 Step 3)。
- 先做一次干净构建(
dotnet build --no-incremental或删除bin/obj),在当前的net10.0目标上建立干净的基线,并记录所有既有警告,便于与迁移后的输出对比。
Step 2:更新目标框架(Update the Target Framework)
在每个
.csproj(若集中管理则在Directory.Build.props)中修改:<!-- Before --> <TargetFramework>net10.0</TargetFramework> <!-- After --> <TargetFramework>net11.0</TargetFramework>对于多目标项目,在
<TargetFrameworks>中添加net11.0或替换net10.0。将所有
Microsoft.Extensions.*、Microsoft.AspNetCore.*、Microsoft.EntityFrameworkCore.*等微软包引用更新到11.0.x版本。若使用中央包管理(Central Package Management,Directory.Packages.props),则在此集中更新版本号。运行
dotnet restore,先解决所有还原错误再继续。运行
dotnet build,捕获全部错误与警告,留待 Step 3 处理。
Step 3:修复源码级破坏与编译错误(Fix source-breaking changes)
根据项目技术领域按需加载对应 reference 文档:
| Reference 文件 | 加载时机 |
|---|---|
| csharp-compiler-dotnet10to11.md | 总是加载(C# 15 编译器破坏性变更) |
| core-libraries-dotnet10to11.md | 总是加载(适用于所有 .NET 11 项目) |
| sdk-msbuild-dotnet10to11.md | 总是加载(SDK 与构建工具变更) |
| aspnetcore-dotnet10to11.md | 项目使用 ASP.NET Core(OpenAPI、Blazor) |
| efcore-dotnet10to11.md | 项目使用 Entity Framework Core |
| cryptography-dotnet10to11.md | 项目使用加密 API、mTLS,或目标为 macOS |
| runtime-jit-dotnet10to11.md | 部署到老旧硬件、嵌入式设备或使用 NativeAOT |
C# 15 编译器源码级破坏性变更
随 .NET 11 SDK 发布的 Roslyn 编译器默认对所有net11.0项目启用 C# 15,以下变更需要逐条排查:
1. Span 集合表达式 safe-context 改为declaration-block(影响:中)
集合表达式的Span<T>/ReadOnlySpan<T>类型 safe-context 修正为declaration-block(此前编译器错误地使用function-member)。在内层作用域创建 span 集合表达式并赋给外层变量时会报错:
// 破坏——新错误 scoped Span<int> items1 = default; foreach (var x in new[] { 1, 2 }) { Span<int> items = [x]; if (x == 1) items1 = items; // error: safe-context is declaration-block } // 修复方案 1:改用数组类型 foreach (var x in new[] { 1, 2 }) { int[] items = [x]; if (x == 1) items1 = items; // ok,通过 int[] 转换为 Span<int> } // 修复方案 2:将集合表达式移到外层作用域 Span<int> items = [0]; foreach (var x in new[] { 1, 2 }) { items[0] = x; if (x == 1) items1 = items; // ok }2.ref readonly合成的委托与局部函数需要InAttribute(影响:低)
编译器为ref readonly返回的方法/λ 合成委托类型时,现在会正确发出需要System.Runtime.InteropServices.InAttribute的元数据;若该特性不可用则报 CS0518:
class RefHelper { private static int value = 42; public void M() { // 若 InAttribute 不可用,可能触发 CS0518 var methodDelegate = this.MethodWithRefReadonlyReturn; var lambdaDelegate = ref readonly int () => ref value; } }局部函数同理:ref readonly int local() => ref x;也可能报 CS0518。修复方式相同——确保引用了定义InAttribute的程序集(通常由默认运行时引用提供)。
3. 特性中的nameof(this.)被禁止(影响:低)
自 C# 12 起被「意外允许」的nameof(this.P)写法现在按语言规范被正式禁止:
// 修复:去掉 this. 限定符 class C { string P; [System.Obsolete(nameof(P))] void M() { } }4. 集合表达式中的with()语义变化(C# 15)(影响:低)
当LangVersion≥ 15 时,集合表达式元素中的with(...)被解释为构造器/工厂参数(新的「collection expression arguments」特性),而非调用名为with的方法:
object x, y, z = ...; object[] items; items = [with(x, y), z]; // C# 14:调用 with() 方法;C# 15:报错 items = [@with(x, y), z]; // 修复:转义为调用名为 'with' 的方法5.dynamic右操作数与接口左操作数的&&/||被禁止(影响:低)
接口类型作为&&/||左操作数、dynamic作为右操作数时,编译器现在直接报错 CS7083(此前编译通过但运行期抛RuntimeBinderException):
void M() { I1 x = new C1(); dynamic y = new C1(); _ = x && y; // error CS7083 } // 修复:将左操作数转换为具体类型或 dynamic _ = (C1)x && y; // valid _ = (dynamic)x && y; // valid6. switch 表达式臂中when的解析变化(影响:低)
(X.Y) when现在被解析为常量模式(X.Y)后接when子句(此前被解析为将when强制转换为(X.Y)的转型表达式),可能导致既有代码编译失败或语义变化,需检查所有使用when的 switch 表达式并调整语法。
7. 顺带了解:C# 15 新增「collection expression arguments」特性(非破坏性)
该特性正是导致上述with()变更的根源,它允许在集合表达式首元素使用with(...)传构造参数:
List<string> names = [with(capacity: values.Count * 2), .. values]; HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO"];核心库与 SDK/MSBuild 的源码级变更
8. SYSLIB0063:NamedPipeClientStream的isConnected参数被弃用(影响:高,对TreatWarningsAsErrors项目)
isConnected参数从未产生任何实际效果——从已有SafePipeHandle创建的管道总是已连接的。.NET 11 提供了不带该参数的新构造函数:
// .NET 10:无警告编译 var pipe = new NamedPipeClientStream(PipeDirection.InOut, isAsync: true, isConnected: true, safePipeHandle); // .NET 11:SYSLIB0063 警告(TreatWarningsAsErrors 时为错误) // 修复:移除 isConnected 参数 var pipe = new NamedPipeClientStream(PipeDirection.InOut, isAsync: true, safePipeHandle);9.Microsoft.OpenApi升级到 v3(影响:中)
Microsoft.AspNetCore.OpenApi的依赖从Microsoft.OpenApi2.x 升级到 3.x,带来 OpenAPI 3.2.0 文档生成能力,但 v2→v3 存在破坏性 API 变更。直接使用OpenApiDocument、OpenApiSchema、OpenApiOperation等类型的代码会产生编译错误。若仅使用 ASP.NET Core OpenAPI 集成(.WithOpenApi()、MapOpenApi())而不直接操作对象模型,则无需改动。
10. EF Core Design 包不再传递依赖(影响:低)
Microsoft.EntityFrameworkCore.Tools与.Tasks不再传递依赖.Design,依赖该传递引用的项目需显式添加:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="11.0.0" PrivateAssets="all" />11.EFOptimizeContextMSBuild 属性移除(影响:低)
<EFOptimizeContext>true</EFOptimizeContext>不再存在,代码生成改由<EFScaffoldModelStage>与<EFPrecompileQueriesStage>控制;当PublishAOT=true时发布阶段自动生成。
12. 其他 SDK 级行为变更(影响:低)
PackAsTool=true搭配自定义NuspecFile时产生新警告NETSDK1235(TreatWarningsAsErrors项目会失败),需移除自定义NuspecFile或确认.nuspec兼容后压制警告;dotnet publish --self-contained现在会正确解析传入值(如--self-contained false真正产生框架依赖发布),需复查构建脚本中的传值是否符合预期。
Step 4:处理运行时行为变更(Address behavioral changes)
这些变更可以正常编译,但会改变运行期行为,需逐项评估影响:
1. DeflateStream/GZipStream 空负载写出头/尾(影响:中)
即使未写入任何数据,DeflateStream与GZipStream现在也会输出合法的格式头/尾(此前空负载产生 0 字节输出):
// .NET 10:输出流为空(0 字节) // .NET 11:输出流包含合法头/尾 using var ms = new MemoryStream(); using (var gz = new GZipStream(ms, CompressionMode.Compress, leaveOpen: true)) { // 什么也不写 } // ms.Length 在 .NET 10 为 0,在 .NET 11 大于 0修复:若代码通过「输出是否为空」判断「没有数据被压缩」,应改判未压缩字节数,或调整长度检查以计入头/尾。
2. MemoryStream 最大容量更新与异常行为变化(影响:中)——复查创建超大 MemoryStream 或依赖特定容量异常类型的代码。
3. TAR 头部校验和验证(影响:中)——TAR 读取 API 现在校验头部校验和,损坏或手工构造的 TAR 文件可能读取失败,需为校验和失败增加错误处理:
using var reader = new TarReader(stream); var entry = reader.GetNextEntry(); // 损坏文件可能抛异常4.ZipArchive.CreateAsync改为急切加载(影响:低)——条目由惰性加载改为急切加载,超大归档的内存占用可能上升。
5.Environment.TickCount与 Windows 超时行为一致(影响:低)——依赖特定回绕/比较模式的代码可能需要调整。
6. macOS 移除 DSA(影响:中,仅 macOS)——DSA 签名/验证在 macOS 上抛异常,建议迁移至 ECDSA(推荐)、RSA 或 Ed25519;Windows/Linux 上 DSA 仍可用(但属遗留算法):
// .NET 11 的 macOS 上破坏 using var dsa = DSA.Create(); var signature = dsa.SignData(data, HashAlgorithmName.SHA256); // 修复:改用其他算法 using var ecdsa = ECDsa.Create(); var signature = ecdsa.SignData(data, HashAlgorithmName.SHA256);7. 日本历法最小支持日期修正(影响:低)——使用极早期日本历法日期的代码可能受影响。
8. 最低硬件要求更新(影响:对老旧硬件部署为高)——详见下文「硬件基线」小节。
9. .NET Framework 应用不再自动设置 Mono 启动目标(影响:低)——在 Linux 上通过 Mono 运行 .NET Framework 应用需显式指定。
10.BackgroundService未处理异常将终止宿主(影响:中,Preview 3)——ExecuteAsync()抛出的未处理异常现在向上传播并停止宿主,此前被静默吞掉:
// .NET 10:异常被静默吞掉,宿主继续运行 // .NET 11:异常传播,宿主停止 protected override async Task ExecuteAsync(CancellationToken stoppingToken) { throw new InvalidOperationException("oops"); // 现在会杀死宿主 } // 修复:为不应因失败而崩溃宿主的后台服务添加异常处理 protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { // ... 工作内容 ... } catch (Exception ex) when (ex is not OperationCanceledException) { _logger.LogError(ex, "Background service failed"); } }11. ZipArchive 读取时校验 CRC32(影响:低-中,Preview 3)——损坏或截断的 ZIP 归档此前被静默接受,现在抛出InvalidDataException,处理部分写入或遗留归档时需增加错误处理。
12. TarWriter 为硬链接输出 HardLink 条目(影响:低,Preview 3)——归档目录中同一 inode 多次出现时,现在写入指向首次出现的HardLink条目而非重复文件数据,消费 .NET 产出 tar 归档的读取方需处理HardLink条目类型。
13. AIA 证书下载默认禁用(影响:中,Preview 3)——服务端客户端证书链验证不再默认通过 AIA 在线下载中间 CA。使用 mTLS 且客户端证书依赖 AIA URL 获取中间 CA 的场景,需:在服务端预装完整证书链;或让客户端发送包含中间 CA 的完整链;或通过X509ChainPolicy.DisableCertificateDownloads = false重新启用 AIA 下载。
14. BlazorVirtualize默认OverscanCount从 3 改为 15(影响:低,Preview 3)——为支持可变高度条目测量,Virtualize<TItem>默认OverscanCount变为 15(QuickGrid仍保持 3)。性能敏感场景请显式设置:<Virtualize OverscanCount="3" />。
15.Microsoft.Data.SqlClient升级到 7.0,Entra ID 认证分离(影响:中,Preview 3)——核心包移除了 Azure/Entra ID 认证依赖(Azure.Core、Azure.Identity、Microsoft.Identity.Client)。使用ActiveDirectoryDefault、ActiveDirectoryManagedIdentity等认证方式时需添加:
<PackageReference Include="Microsoft.Data.SqlClient.Extensions.Azure" Version="7.0.0" />16.SqlVector<T>默认排除出 SELECT(影响:低,Preview 3)——实体物化时向量属性返回null,但仍可用于WHERE/ORDER BY向量搜索;需用显式投影引入向量值:.Select(b => new { b.Id, b.Embedding })。
17. SQLitePCLRaw 加密 bundle 移除(影响:中,Preview 3)——SQLitePCLRaw 3.0(Microsoft.Data.Sqlite11 使用)移除了bundle_e_sqlcipher等 bundle 包,需改用 SQLite Encryption Extension(SEE)、Zetetic 的 SQLCipher 或SQLite3MultipleCiphers-NuGet。
18. NativeAOT Unix 原生库输出带lib前缀(影响:低,Preview 3)——Linux/macOS 上的共享/原生库输出遵循 Unix 惯例增加lib前缀(如libMyLib.so取代MyLib.so),需同步更新构建脚本、部署流水线或按旧文件名引用的 P/Invoke 声明。
专属领域补充:EF Core 11 与运行时/硬件基线
EF Core Cosmos 同步 I/O 完全移除(影响:中,Preview 1)——EF Core 10 中同步 I/O 默认不支持但可特殊 opt-in;EF Core 11 中调用任何同步 I/O API 都总是抛异常,且没有 opt-in 恢复旧行为。受影响的 API 包括ToList()、First()、Single()、Count()等同步 LINQ 运算符与SaveChanges()。原因是同步阻塞异步方法(sync-over-async)会导致死锁与性能问题,而 Cosmos SDK 仅支持异步:
// EF Core 11 中破坏——总是抛异常 var items = context.Items.ToList(); context.SaveChanges(); // 修复:改用异步等价物 var items = await context.Items.ToListAsync(); await context.SaveChangesAsync();完整映射:ToList()→ToListAsync()、First()→FirstAsync()、Single()→SingleAsync()、Count()→CountAsync()、SaveChanges()→SaveChangesAsync()、Any()→AnyAsync()。同时注意方法需返回Task<T>且调用方需改为await。此外(Preview 1)Cosmos 拥有的空集合现在返回空集合而非null,需将if (entity.Items is null)改为if (entity.Items.Count == 0);(Preview 3)程序集中无迁移时调用Migrate()/MigrateAsync()默认抛异常而非静默记录,可用options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsNotFound))压制。
最低硬件要求(影响:对老旧硬件部署为高)——.NET 11 更新了 x86/x64 与 Arm64 的最低硬件基线:
- x86/x64:JIT/AOT 最低要求从
x86-64-v1提升到x86-64-v2(新增要求CX16、POPCNT、SSE3、SSSE3、SSE4.1、SSE4.2);Windows/Linux 的 ReadyToRun(R2R)目标提升到x86-64-v3(新增AVX、AVX2、BMI1、BMI2、F16C、FMA、LZCNT、MOVBE),达不到 R2R 目标的硬件启动时会有额外 JIT 开销。 - Arm64:Windows 基线提升为要求
LSE(Load-Store Exclusive),R2R 目标更新为armv8.2-a + RCPC;Linux 最低硬件不变(仍支持 Raspberry Pi),R2R 目标更新为armv8.0-a + LSE;Apple 无变化。
从 .NET 11 起,在老旧硬件上运行会直接失败并打印:
The current CPU is missing one or more of the baseline instruction sets.
修复:验证所有部署目标满足新要求——x86/x64 上约 2013 年及之后的 CPU 均可;Windows Arm64 需确认 LSE 支持(所有兼容 Windows 11 的 Arm64 设备均可)。上述硬件最低要求的完整对照表(各 OS 的 JIT/AOT 最低要求与 R2R 目标)见 runtime-jit-dotnet10to11.md。
Step 5:更新基础设施(Update infrastructure)
1. Dockerfile:将基础镜像从 10.0 更新到 11.0:
# Before FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:10.0 # After FROM mcr.microsoft.com/dotnet/sdk:11.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:11.02. CI/CD 流水线:更新 SDK 版本引用。若使用global.json,在现有文件中更新sdk.version,同时保留其他键(如rollForward与测试配置):
{ "sdk": { - "version": "10.0.100", - "rollForward": "latestFeature" + "version": "11.0.100-preview.3", + "rollForward": "latestFeature" }, "otherSettings": { "...": "..." } }3. 硬件部署目标:确认所有部署目标满足新的最低硬件要求(x86/x64 为x86-64-v2,Windows Arm64 为LSE)。
Step 6:验证(Verify)
- 完整干净构建:
dotnet build --no-incremental - 运行全部测试:
dotnet test - 若应用容器化,构建并测试容器镜像
- 冒烟测试,重点检查:
- 空流的压缩行为;
- TAR 文件读取(校验和验证与 HardLink 条目);
- EF Core Cosmos DB 操作(必须异步);
- macOS 上的 DSA 使用;
- 高内存占用的 MemoryStream 使用;
- Span 集合表达式赋值;
- BackgroundService 异常处理;
- mTLS / 客户端证书链验证;
- EF Core SQL Server 搭配 Entra ID 认证;
- Unix 上 NativeAOT 输出文件名。
- 复查 diff,确保没有引入非预期的行为变更。
Reference 文档体系
references/目录按技术领域组织破坏性变更详情,迁移时只加载与项目相关的 reference:
| Reference 文件 | 加载时机 |
|---|---|
| csharp-compiler-dotnet10to11.md | 总是加载(C# 15 编译器破坏性变更) |
| core-libraries-dotnet10to11.md | 总是加载(适用于所有 .NET 11 项目) |
| sdk-msbuild-dotnet10to11.md | 总是加载(SDK 与构建工具变更) |
| aspnetcore-dotnet10to11.md | 项目使用 ASP.NET Core(OpenAPI、Blazor) |
| efcore-dotnet10to11.md | 项目使用 Entity Framework Core |
| cryptography-dotnet10to11.md | 项目使用加密 API、mTLS,或目标为 macOS |
| runtime-jit-dotnet10to11.md | 部署到老旧硬件、嵌入式设备或使用 NativeAOT |
仓库内的验证样例
本技能在仓库中配有对应的评测用例 tests/dotnet-upgrade/migrate-dotnet10-to-dotnet11/eval.yaml,其中覆盖了典型的迁移场景,可作为理解各变更落点的实战参考:
- 控制台应用 + 压缩/TAR:
GZipStream空负载写出头/尾、TAR 校验和验证、ZipArchive.CreateAsync急切加载、MemoryStream 容量上限; - C# 15 编译器变更:Span safe-context、
nameof(this.)、with()集合表达式元素; - EF Core Cosmos 同步 API:确认同步 I/O 完全移除且无 opt-in;
- 老旧硬件部署:
x86-64-v2基线导致 2012 年硬件启动失败、Raspberry Pi 4(Arm64 Linux)仍受支持、Surface Pro X(SQ1)满足 LSE; - macOS DSA:运行时
DSA.Create()失败,改用 ECDSA/RSA; - TFM + Docker + global.json 基础更新;
dynamic运算符与ref readonly委托:CS7083 与 CS0518;- BackgroundService 异常与 ZipArchive CRC32;
- EF Core SQL Server Entra ID 认证与 Design 依赖;
- ASP.NET Core OpenAPI 定制与 Blazor Virtualize;
- mTLS 与 AIA 证书链验证。
将这些场景与上文各 Step 一一对应,即可在真实迁移中快速定位每个编译错误与运行期异常属于哪类破坏性变更,并套用对应的修复模式。整体遵循「按逻辑边界提交」的策略,确保 .NET 10 → .NET 11 的升级过程可控、可评审、可回退。
【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考