mcpField
D
dotnet-native-aot

dotnet-native-aot

github.com/wshaddix开发8674 次安装35 周前更新
代码仓库

关于 dotnet-native-aot

面向 .NET 8 及以上版本开发者的 Native AOT 编译指南,覆盖发布配置、裁剪分析、类型保留、反射规避和二进制体积优化。也介绍 P/Invoke 与自包含部署。

主要功能

  1. 01Native AOT 发布配置
  2. 02AOT 与裁剪诊断分析器
  3. 03ILLink 描述符和类型保留
  4. 04反射规避的编码模式
  5. 05P/Invoke 与二进制优化
  6. 06自包含容器部署

适用场景

  1. 01为控制台应用启用 Native AOT 发布
  2. 02检查项目的 AOT 与裁剪兼容问题
  3. 03保留反射使用所需的类型
  4. 04减少 AOT 二进制和容器体积

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-native-aot

安装后在 Claude Code 中输入/dotnet-native-aot确认已加载。

详细介绍

dotnet-native-aot

面向 .NET 8+ 应用的完整 Native AOT 编译流程:PublishAot 配置、用于保留类型的 ILLink 描述符 XML、无反射编码模式、P/Invoke 注意事项、二进制大小优化、使用 runtime-deps 基础镜像进行自包含部署,以及诊断分析器(EnableAotAnalyzer/EnableTrimAnalyzer)。

**版本假设:**以 .NET 8.0+ 为基准。Native AOT 支持 .NET 8 中推出的 ASP.NET Core Minimal API 和控制台应用。.NET 9 改进了裁剪警告和库兼容性。.NET 10 增强了请求委托生成器,并扩大了 Minimal API 的 AOT 支持范围。

**范围边界:**本技能负责通用的 .NET Native AOT 编译,包括发布流程、MSBuild 配置、类型保留、P/Invoke 和大小优化。MAUI 专用的 iOS/Mac Catalyst AOT(发布配置文件、平台专属的库兼容性)请参阅 [skill:dotnet-maui-aot]。AOT 优先的应用设计模式(优先使用源代码生成而非反射、DI、序列化选择)请参阅 [skill:dotnet-aot-architecture]。安全支持裁剪的库编写请参阅 [skill:dotnet-trimming]。Blazor/Uno 的 WASM AOT 请参阅 [skill:dotnet-aot-wasm]。

**范围之外:**MAUI iOS/Mac Catalyst AOT 流程请参阅 [skill:dotnet-maui-aot]。源生成器编写(Roslyn API)请参阅 [skill:dotnet-csharp-source-generators]。DI 容器模式请参阅 [skill:dotnet-csharp-dependency-injection]。序列化详情请参阅 [skill:dotnet-serialization]。容器部署编排请参阅 [skill:dotnet-containers]。

交叉引用:[skill:dotnet-aot-architecture](AOT 优先的设计模式)、[skill:dotnet-trimming](安全支持裁剪的库编写)、[skill:dotnet-aot-wasm](WebAssembly AOT)、[skill:dotnet-maui-aot](MAUI 专用 AOT)、[skill:dotnet-containers](runtime-deps 基础镜像)、[skill:dotnet-serialization](安全支持 AOT 的序列化)、[skill:dotnet-csharp-source-generators](作为 AOT 助力的源代码生成)、[skill:dotnet-csharp-dependency-injection](安全支持 AOT 的 DI)、[skill:dotnet-native-interop](通用 P/Invoke 模式和跨平台库解析)。


PublishAot 配置

启用 Native AOT

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>
# Publish as Native AOT
dotnet publish -c Release -r linux-x64

# Publish for specific targets
dotnet publish -c Release -r win-x64
dotnet publish -c Release -r osx-arm64
MSBuild 属性:应用与库

应用和库使用不同的 MSBuild 属性。不要混用。

应用(控制台应用、ASP.NET Core Minimal API):

<PropertyGroup>
  
  <PublishAot>true</PublishAot>

  
  <EnableAotAnalyzer>true</EnableAotAnalyzer>
  <EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

库(NuGet 包、共享类库):

<PropertyGroup>
  
  <IsAotCompatible>true</IsAotCompatible>
  
  <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

IsAotCompatible 和 IsTrimmable 会分别自动启用 AOT 和裁剪分析器。库项目中不要同时设置 PublishAot——库不会作为独立可执行文件发布。


诊断分析器

在开发期间启用 AOT 和裁剪分析器,以便在发布前发现问题:

<PropertyGroup>
  <EnableAotAnalyzer>true</EnableAotAnalyzer>
  <EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
不发布即可进行分析

在 dotnet build 期间运行分析,无需完整发布:

# Analyze AOT compatibility without publishing
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true

# See per-occurrence warnings (not grouped by assembly)
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true /p:TrimmerSingleWarn=false

这会报告 IL2xxx(裁剪)和 IL3xxx(AOT)警告,但不会生成原生二进制文件,从而在开发期间快速获得反馈。

常见诊断代码
代码类别含义
IL2026裁剪成员带有 [RequiresUnreferencedCode]——裁剪后可能会出错
IL2046裁剪基类/派生类之间的裁剪特性不匹配
IL2057-IL2072裁剪各种裁剪器无法分析的反射用法
IL3050AOT成员带有 [RequiresDynamicCode]——会在运行时生成代码
IL3051AOT[RequiresDynamicCode] 特性不匹配

用于保留类型的 ILLink 描述符

当代码使用裁剪器无法静态分析的反射时,请使用 ILLink 描述符 XML 来保留类型。不要使用旧版 RD.xml——它是 .NET Native/UWP 格式,现代 .NET AOT 会静默忽略它。

ILLink 描述符 XML

<linker>
  
  <assembly fullname="MyApp">
    <type fullname="MyApp.Models.LegacyConfig" preserve="all" />
    <type fullname="MyApp.Services.PluginLoader">
      <method name="LoadPlugin" />
    </type>
  </assembly>

  
  <assembly fullname="IncompatibleLibrary" preserve="all" />
</linker>

<ItemGroup>
  <TrimmerRootDescriptor Include="ILLink.Descriptors.xml" />
</ItemGroup>
[DynamicDependency] 特性

在代码中有针对性地保留内容(对于小范围、局部场景,优先于 ILLink XML):

using System.Diagnostics.CodeAnalysis;

// Preserve a specific method
[DynamicDependency(nameof(LegacyConfig.Initialize), typeof(LegacyConfig))]
public void ConfigureApp() { /* ... */ }

// Preserve all public members
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PluginBase))]
public void LoadPlugins() { /* ... */ }
适用场景
场景方案
一两个方法或类型[DynamicDependency] 特性
整个程序集或许多类型ILLink 描述符 XML
不支持 AOT 的第三方库ILLink 描述符 XML 或 <TrimmerRootAssembly>
使用已分析反射的自有代码重构为源生成器(长期来看是最佳方案)

无反射模式

Native AOT 最适合完全避免运行时反射的代码。请使用编译时替代方案替换反射模式。

反射模式AOT 安全的替代方案
Activator.CreateInstance<T>()工厂方法或显式使用 new T()
用于映射的 Type.GetProperties()Mapperly 源生成器或手动映射
用于 DI 扫描的 Assembly.GetTypes()显式调用 services.AddScoped<T>()
JsonSerializer.Deserialize<T>(json)JsonSerializer.Deserialize(json, Context.Default.T)
用于分派的 MethodInfo.Invoke()根据类型使用 switch 或接口分派

请参阅 [skill:dotnet-aot-architecture],了解全面的 AOT 优先设计模式。


P/Invoke 注意事项

对原生库的 P/Invoke(平台调用)通常可与 Native AOT 配合使用,但需要注意以下事项:

直接 P/Invoke(首选)
// Direct P/Invoke -- AOT-compatible, no runtime marshalling overhead
[LibraryImport("libsqlite3", EntryPoint = "sqlite3_open")]
internal static partial int Sqlite3Open(
    [MarshalAs(UnmanagedType.LPStr)] string filename,
    out nint db);

使用 [LibraryImport](.NET 7+)替代 [DllImport]——它通过源生成器在编译时生成封送代码,因此完全兼容 AOT。

DllImport 与 LibraryImport 的比较
特性AOT 兼容性封送
[DllImport]部分支持——部分封送需要运行时代码生成运行时封送
[LibraryImport]完全支持——编译时源生成编译时封送
// Migrate from DllImport to LibraryImport
// Before:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);

// After:
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool CloseHandle(IntPtr hObject);
原生库部署

以 Native AOT 发布时,原生库(.so、.dylib、.dll)必须与二进制文件放在同一目录中:

<ItemGroup>
  
  <NativeLibrary Include="libs/libcustom.so" />
</ItemGroup>

大小优化

缩减二进制文件大小的选项
<PropertyGroup>
  <PublishAot>true</PublishAot>

  
  <StripSymbols>true</StripSymbols>

  
  <OptimizationPreference>Size</OptimizationPreference>

  
  <InvariantGlobalization>true</InvariantGlobalization>

  
  <StackTraceSupport>false</StackTraceSupport>

  
  <EventSourceSupport>false</EventSourceSupport>
</PropertyGroup>
典型二进制文件大小
配置控制台应用ASP.NET Minimal API
默认 AOT~10-15 MB~15-25 MB
+ StripSymbols~8-12 MB~12-20 MB
+ 大小优化~6-10 MB~10-18 MB
+ InvariantGlobalization~4-8 MB~8-15 MB
大小分析
# Analyze what contributes to binary size
dotnet publish -c Release -r linux-x64 /p:PublishAot=true

# Use sizoscope (community tool) for detailed size analysis
# https://github.com/AdrianEddy/sizoscope

使用 runtime-deps 进行自包含部署

Native AOT 会生成包含 .NET 运行时的自包含二进制文件。由于运行时已嵌入二进制文件,请使用 runtime-deps 基础映像,以尽可能减小容器大小。

# Build stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -r linux-x64 -o /app/publish

# Runtime stage -- use runtime-deps, not aspnet or runtime
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS runtime
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["./MyApp"]

runtime-deps 映像仅包含操作系统级依赖项(libc、OpenSSL 等),不包含 .NET 运行时。这是 AOT 发布应用可用的最小基础映像(约 30 MB)。请参阅 [skill:dotnet-containers],了解完整的容器模式。


ASP.NET Core Native AOT

Minimal API 支持(.NET 8+)

ASP.NET Core Minimal API 支持 Native AOT。MVC 控制器不兼容 AOT(它们依赖反射来实现模型绑定、筛选器和路由)。

var builder = WebApplication.CreateSlimBuilder(args);

// Use source-generated JSON context
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});

var app = builder.Build();

app.MapGet("/api/products/{id}", (int id) =>
    Results.Ok(new Product(id, "Widget")));

app.Run();

[JsonSerializable(typeof(Product))]
internal partial class AppJsonContext : JsonSerializerContext { }

record Product(int Id, string Name);
CreateSlimBuilder 与 CreateBuilder 的比较
方法AOT 支持包含内容
WebApplication.CreateSlimBuilder()完全支持最少的服务,不包含 MVC 和 Razor
WebApplication.CreateBuilder()部分支持完整功能集,部分功能需要反射

Native AOT 应用请使用 CreateSlimBuilder。它会排除需要运行时代码生成的功能。

.NET 10 ASP.NET Core AOT 改进

.NET 10 改进了 ASP.NET Core 和运行时 Native AOT 技术栈。将目标框架设为 net10.0 即可自动受益。

<PropertyGroup>
  <TargetFramework>net10.0</TargetFramework>
  <PublishAot>true</PublishAot>
</PropertyGroup>

Request Delegate Generator 改进: 为 Minimal API 端点生成请求委托的源生成器在 .NET 10 中支持更多参数绑定场景,包括更多 TypedResults 返回类型和复杂绑定模式。这减少了手动变通方案的需求;在 .NET 8/9 中,生成器无法为某些端点签名生成 AOT 安全代码,因此需要使用这些方案。

缩小链接器警告范围: 许多之前会产生修剪/AOT 警告(IL2xxx/IL3xxx)的 ASP.NET Core 框架 API 已添加注释或经过重构,以兼容 AOT。从 .NET 9 升级到 .NET 10 的项目在使用 PublishAot 发布时,将看到更少的误报链接器警告。

webapiaot 模板中的 OpenAPI: webapiaot 项目模板现在默认通过 Microsoft.AspNetCore.OpenApi 生成 OpenAPI 文档,因此以 AOT 发布的 API 无需额外设置即可自动生成 API 文档。

运行时 NativeAOT 代码生成: .NET 10 运行时改进了结构体参数的 AOT 代码生成,增强了循环反转优化,并改进了方法去虚拟化——无需修改代码即可提升 AOT 发布应用的吞吐量。

Blazor Server 和 SignalR: 在 .NET 10 中,Blazor Server 和 SignalR 仍不支持 Native AOT。Blazor WebAssembly AOT(客户端编译)是另一个单独的问题,详见 [skill:dotnet-aot-wasm]。对于 Blazor Server 应用,请继续使用 JIT 部署。

兼容性概览(.NET 10):

功能AOT 支持
gRPC完全支持
Minimal APIs部分支持(大多数场景可用)
MVC不支持
Blazor Server不支持
SignalR不支持
JWT Authentication完全支持
CORS、HealthChecks、OutputCaching完全支持
WebSockets、StaticFiles完全支持

Agent 注意事项

  1. 不要在库项目中使用 PublishAot。 库应使用 IsAotCompatible(它会自动启用 AOT 分析器)。PublishAot 用于生成独立可执行文件的应用程序。
  2. 不要使用旧版 RD.xml 保留类型。 RD.xml 是 .NET Native/UWP 格式,在现代 .NET AOT 中会被静默忽略。请改用 ILLink 描述符 XML 文件和 [DynamicDependency] 属性。
  3. 不要在新的 AOT 代码中使用 [DllImport]。 请使用 [LibraryImport](.NET 7+),它会在编译时生成封送代码。[DllImport] 可能需要 AOT 中不可用的运行时封送功能。
  4. 不要对 AOT API 使用 WebApplication.CreateBuilder()。 请使用 CreateSlimBuilder(),它会排除大量依赖反射的功能。CreateBuilder() 包含与 AOT 不兼容的 MVC 基础设施。
  5. 不要使用 dotnet publish --no-actual-publish 进行分析。 该标志不存在。请使用 dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true,以在不发布的情况下获取诊断警告。
  6. 不要假定 MVC 控制器可与 Native AOT 配合使用。 MVC 在模型绑定、操作筛选器和路由方面依赖反射。对于以 AOT 发布的 Web 应用,请使用 Minimal APIs。

参考资料

评论

支持 Markdown