长期支持版本意味着什么
.NET 采用双轨发布:偶数版本为长期支持版本,支持周期三年;奇数版本为标准支持,只有约十八个月。选择长期支持版本意味着你能在较长周期内只接收安全修复与稳定性改进,而不必频繁跟进破坏性变更,这对生产系统是实实在在的成本节约。
版本选型的第一原则是看支持周期,第二原则才看新特性——一个已经停止维护的框架,性能再好也是资产负担。
- 运行时优化每一代都在 JIT、集合与字符串处理上做持续改进。
- 语言配套新版本语言特性与运行时能力同步可用,无需额外配置。
- 容器友好官方镜像持续精简,镜像体积与启动时间都在下降。
- 安全修复支持期内持续获得漏洞修复,无需自行打补丁。
Minimal API:更少的样板代码
Minimal API 用一组链式调用替代控制器与特性路由,适合接口数量不多、职责清晰的小型服务。路由参数从方法签名自动绑定,参数校验可以直接写在处理函数里;当接口规模变大后,再按功能拆成多个扩展方法注册,依然能保持结构清晰。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IArticleStore, MemoryArticleStore>();
var app = builder.Build();
app.MapGet("/api/articles/{id:int}", async (int id, IArticleStore store) =>
{
var article = await store.FindAsync(id);
return article is null ? Results.NotFound() : Results.Ok(article);
});
app.Run();
这段代码体现了框架设计的取向:依赖注入直接体现在参数上,中间件按需添加,返回值用 Results 静态方法表达状态码与内容。它比控制器版本少了一层类与特性,代价是当参数与校验规则复杂时,需要自己组织代码结构。
依赖注入与配置体系
内置容器按生命周期管理服务:单例全局唯一、作用域随请求创建、瞬态每次解析都新建。绝大多数故障源于生命周期错配——把作用域服务注入单例,容器无法提供,运行时就抛异常;反过来,把本该单例的有状态服务注册成瞬态,则会出现状态丢失或资源重复创建。
- 单例无状态工具、缓存与配置读取器,注意必须线程安全。
- 作用域数据库上下文、请求级缓存的默认选择。
- 瞬态轻量无状态对象,创建成本低,不要滥用。
配置体系则把命令行参数、环境变量、配置文件、密钥管理等来源合并成统一的取值接口,越靠后的来源优先级越高。这个顺序让同一份代码天然支持「本地用文件、线上用环境变量」,避免把密钥提交进仓库。
原生 AOT 与启动性能
原生 AOT 在发布时把中间语言直接编译为机器码,产物不依赖运行时即时编译,启动时间可降到毫秒级,内存占用也更低,非常适合容器与命令行工具。代价是它要求代码路径在编译期可静态分析:不能依赖运行时代码生成,反射需要显式声明,部分动态特性不可用。
dotnet publish -c Release -r linux-x64 --self-contained \
/p:PublishAot=true /p:InvariantGlobalization=true
如果项目大量依赖反射或动态代理,强行开启 AOT 会付出很高的改造代价。这时更务实的选择是「裁剪 + 就绪运行」:裁剪掉未使用的程序集减小体积,把耗时的初始化提前到发布阶段完成,从而缩短首次请求的响应时间。
容器化部署与可观测性
容器化推荐使用多阶段构建:构建阶段安装 SDK 完成编译,运行阶段只拷贝发布产物并使用精简的基础镜像。这样镜像里既没有源码也没有编译工具,体积小、攻击面小,构建缓存也更容易命中。运行时通过环境变量注入配置,进程以非 root 用户启动,健康检查指向一个轻量接口。
可观测性三件套应当在上线前接好:结构化日志记录请求标识与耗时、指标暴露请求量延迟与错误率、分布式追踪串联跨服务调用。缺少任何一项,线上排查都只能靠猜;配齐之后,定位一个慢请求通常只需要几分钟。
升级到 .NET 8 的注意事项
升级的稳妥路径是分步走:先更新目标框架与依赖版本,在本地跑通全部测试;再对照官方的破坏性变更清单逐项核对,重点关注序列化行为、默认超时、加密算法可用性与全球化数据的差异;最后在小流量环境观察一段时间再全量发布。跳过任何一步,都可能把一个只在特定输入下才出现的问题带到生产。
依赖兼容性往往是主要阻力。第三方库尚未发布支持新框架的版本时,可以先用兼容模式引用旧版本程序集,同时把该依赖标记为待清理项,避免兼容层长期沉淀成技术债。容器镜像与基础镜像的版本也要同步更新,否则会出现「本地正常、容器报错」的环境不一致。
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
把警告当成错误是一种低成本的质量控制:升级过程中编译器产生的每一条警告都值得看一眼,其中相当一部分正是未来运行期问题的前兆。
小结与延伸阅读
.NET 8 的关键词是「更少的样板与更快的启动」:Minimal API 减少结构开销,AOT 改善冷启动,容器镜像持续精简。
- 语言基础回看《C# 语言核心:.NET 开发基石》。
- 写桌面客户端时读《WinUI 3 桌面应用开发入门》。
- 需要自动化部署与运维脚本,读《PowerShell 自动化脚本实战》。