Native AOT 编译需要 .NET 7+ 且项目 SDK 必须为 Microsoft.NET.Sdk
低于 .NET 7 的版本不支持 Native AOT;即使装了高版本 SDK,若项目文件仍用
Microsoft.NET.Sdk.Web或
Microsoft.NET.Sdk.Worker,
dotnet publish会直接忽略
--aot参数或报错“PublishAot is not supported”。必须显式改用基础 SDK,并手动处理宿主逻辑(比如 Web 项目要自己调用
WebApplication.CreateBuilder,不能依赖模板自动生成的宿主)。 检查项目文件开头是否为
<project sdk="Microsoft.NET.Sdk"></project>移除
<frameworkreference include="Microsoft.AspNetCore.App"></frameworkreference>等隐式框架引用,改用 NuGet 包(如
Microsoft.AspNetCore.App.Ref)并确认其支持 AOT 避免使用反射动态加载程序集(
Assembly.LoadFrom)、
System.Text.Json的未标注序列化器、未提前注册的 DI 服务——这些在 AOT 下会静默失败或运行时报
MissingMethodException
dotnet publish
必须指定 --aot
和 -r
(RuntimeIdentifier)
AOT 编译不是编译开关,而是发布阶段的跨平台原生代码生成行为,不指定
-r会导致构建失败:“The RuntimeIdentifier must be set for native AOT publish.”。目标平台决定生成的二进制格式(如
win-x64、
linux-x64、
osx-arm64),且不能用
any或省略。 正确命令示例:
dotnet publish -c Release -r win-x64 --aot若需调试符号,加
--strip-symbols false(默认开启 strip,导致 pdb 不可用) Windows 上若提示 “LLVM not found”,需安装
llvm并确保
clang++在 PATH 中;Linux/macOS 同理,AOT 依赖系统级 C++ 工具链
第三方库必须声明 AotCompatibility
或提供 AOT 友好 API
很多 NuGet 包(尤其是含反射、表达式树、动态代码生成的)默认不兼容 AOT。.NET SDK 会在 publish 时扫描引用并报错,例如:
ILLink failed: Unresolved assembly 'Newtonsoft.Json'。不是所有包都已适配——比如旧版
Newtonsoft.Json不支持,必须升级到 13.0.3+ 并启用
JsonSerializerOptions.AotCompilation(部分场景仍需替换为
System.Text.Json)。 优先选用标有
<istrimmable>true</istrimmable>和
<supportsaot>true</supportsaot>的包(可在
.nuspec或源码仓库中查) 数据库驱动如
Npgsql需 8.0+,
Microsoft.Data.Sqlite需 8.0+,否则连接字符串解析等环节会因反射失败 日志、配置、验证等基础功能尽量用
Microsoft.Extensions.*8.0+ 版本,避免自行封装泛型工厂或未标注
[RequiresUnreferencedCode]的扩展方法
调试和体积优化的实际取舍点
AOT 输出是单文件原生可执行文件,无运行时依赖,但启动快 ≠ 全局快:JIT 的运行时优化(如内联热点方法、PGO)在 AOT 中不可用,某些计算密集型路径可能变慢。同时,关闭 trim(
<trimmode>none</trimmode>)会让体积暴涨 2–5 倍,而过度 trim 又易引发
MissingFieldException。 开发期用
dotnet run -c Debug --no-build --aot快速验证基本流程(仅限支持的平台) 发布前务必开启 trim:
<trimmode>partial</trimmode>(默认)或
link,并配合
<publishtrimmed>true</publishtrimmed>若遇到运行时报“method not found”,先检查是否漏加
[DynamicDependency]或
[UnconditionalSuppressMessage],再用
dotnet publish --no-restore -bl查看 ILLink 日志定位裁剪点 AOT 编译真正难的不是命令敲对,而是把整个应用的反射、动态类型、配置绑定、序列化路径全部显式收口——稍有遗漏,错误就藏在运行时,且堆栈不友好。建议从小型控制台工具开始试,别一上来就压 Web API。
