Native AOT 原生编译
大约 15 分钟约 4465 字
Native AOT 原生编译
简介
Native AOT(Ahead-of-Time)是 .NET 8 引入的原生编译技术,将 C# 代码直接编译为平台原生的机器码,无需 .NET 运行时。编译后的程序启动极快、内存占用小、部署简单(单文件)。适合云原生、CLI 工具、微服务等对启动速度和体积敏感的场景。
AOT 编译的工作原理
源代码 (.cs)
|
v
IL 中间语言
|
v
.NET SDK + Native AOT 编译器 (crossgen2)
|
v
Native Library (libapp.so / app.dll + app.exe)
|
v
平台原生机器码(无运行时依赖)与传统 JIT(Just-in-Time)编译不同,AOT 在发布时完成所有编译工作。这意味着:
- JIT 模式:源代码 -> IL -> 运行时加载 -> 运行时编译为机器码 -> 执行(启动时需要编译)
- AOT 模式:源代码 -> IL -> 发布时编译为机器码 -> 直接执行(无需运行时编译器)
为什么需要 Native AOT
在云原生和微服务场景中,传统的 .NET JIT 编译模式面临以下挑战:
| 挑战 | 影响 | AOT 如何解决 |
|---|---|---|
| 冷启动慢 | Serverless 函数响应延迟高 | 毫秒级启动 |
| 内存占用大 | 容器密度低,成本高 | 去掉 JIT 编译器,减少 50%+ 内存 |
| 部署复杂 | 需要安装 .NET 运行时 | 单文件,无需运行时 |
| 攻击面大 | JIT 编译器是潜在攻击向量 | 去掉 JIT,减少攻击面 |
特点
项目配置
启用 Native AOT
<!-- 项目文件配置 -->
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
<!-- ===== 可选优化项 ===== -->
<!-- 编译优化偏好:Speed 或 Size -->
<OptimizationPreference>Speed</OptimizationPreference>
<!-- 禁用全球化支持(如果不需要非 Invariant 区域性) -->
<!-- 可减少约 10-15MB 体积 -->
<InvariantGlobalization>true</InvariantGlobalization>
<!-- 禁用 EventSource 支持(如果不需要 ETW 事件) -->
<EventSourceSupport>false</EventSourceSupport>
<!-- 禁用 HTTP Activity 传播(如果不需要分布式追踪的 Activity) -->
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<!-- 裁剪模式:full 会裁剪未使用的代码 -->
<TrimMode>full</TrimMode>
<!-- 启用 AOT 兼容性分析(编译时检查) -->
<IsAotCompatible>true</IsAotCompatible>
<!-- 生成调试符号 -->
<StripSymbols>false</StripSymbols>
</PropertyGroup>
</Project>不同项目类型的 AOT 支持
<!-- ASP.NET Core Web API(完全支持) -->
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
</PropertyGroup>
</Project>
<!-- 控制台应用(完全支持) -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
<OutputType>Exe</OutputType>
</PropertyGroup>
</Project>
<!-- 类库项目(标记 AOT 兼容但不编译) -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
</Project>
<!-- Worker Service(后台任务,支持) -->
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
</PropertyGroup>
</Project>发布命令详解
# 基本发布(Linux x64)
dotnet publish -c Release -r linux-x64
# 基本发布(Windows x64)
dotnet publish -c Release -r win-x64
# 基本发布(macOS ARM64)
dotnet publish -c Release -r osx-arm64
# 优化体积(优先减小二进制体积)
dotnet publish -c Release -r linux-x64 -p:OptimizationPreference=Size
# 优化速度(优先运行时性能)
dotnet publish -c Release -r linux-x64 -p:OptimizationPreference=Speed
# 保留调试符号(用于生产调试)
dotnet publish -c Release -r linux-x64 -p:PublishAot=true -p:StripSymbols=false
# 交叉编译(在 Windows 上编译 Linux 二进制)
dotnet publish -c Release -r linux-musl-x64
# 查看裁剪/AOT 警告
dotnet publish -c Release -r linux-x64 2>&1 | grep -i "trim\|aot"
# 自定义输出路径
dotnet publish -c Release -r linux-x64 -o ./publish/linux-x64支持的运行时标识符(RID)
| 平台 | RID | 说明 |
|---|---|---|
| Linux (x64) | linux-x64 | 最常用的服务器平台 |
| Linux (ARM64) | linux-arm64 | ARM 服务器、树莓派 |
| Linux Musl (x64) | linux-musl-x64 | Alpine Linux,Docker 常用 |
| Windows (x64) | win-x64 | Windows 服务器 |
| Windows (ARM64) | win-arm64 | ARM Windows 设备 |
| macOS (x64) | osx-x64 | Intel Mac |
| macOS (ARM64) | osx-arm64 | Apple Silicon |
AOT 友好的 API
JSON 序列化
JSON 序列化是 AOT 环境中最常见的兼容性问题来源。传统的 JsonSerializer 依赖反射,在 AOT 模式下需要使用 Source Generator。
// ============================================
// 第一步:定义 Source Generator 上下文
// ============================================
using System.Text.Json.Serialization;
[JsonSerializable(typeof(User))]
[JsonSerializable(typeof(List<User>))]
[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(PagedResult<User>))]
[JsonSerializable(typeof(ApiResponse<User>))]
public partial class MyJsonContext : JsonSerializerContext
{
// 可选:自定义默认选项
public static MyJsonContext Shared { get; } = new(
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false
});
}
// ============================================
// 第二步:在 Minimal API 中注册
// ============================================
var builder = WebApplication.CreateBuilder(args);
// 方式 A:全局配置(推荐)
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolver = MyJsonContext.Default;
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
// 方式 B:单独配置每个端点
var app = builder.Build();
app.MapGet("/api/users", (IUserService service) =>
{
return Results.Ok(service.GetAll());
})
.WithName("GetUsers");
app.MapPost("/api/users", (User user, IUserService service) =>
{
return Results.Created($"/api/users/{user.Id}", service.Create(user));
})
.WithName("CreateUser");
app.Run();
// ============================================
// 第三步:手动序列化/反序列化
// ============================================
// 序列化
string json = JsonSerializer.Serialize(user, MyJsonContext.Default.User);
// 反序列化
var user2 = JsonSerializer.Deserialize(json, MyJsonContext.Default.User);
// 列表序列化
string listJson = JsonSerializer.Serialize(
users, MyJsonContext.Default.ListUser);
// 使用自定义选项
string customJson = JsonSerializer.Serialize(
user, MyJsonContext.Shared.User);处理多态类型
// 多态序列化需要额外的 [JsonDerivedType] 标记
[JsonDerivedType(typeof(CashPayment), typeDiscriminator: "cash")]
[JsonDerivedType(typeof(CreditCardPayment), typeDiscriminator: "credit")]
[JsonDerivedType(typeof(WechatPayment), typeDiscriminator: "wechat")]
[JsonSerializable(typeof(Payment))]
[JsonSerializable(typeof(CashPayment))]
[JsonSerializable(typeof(CreditCardPayment))]
[JsonSerializable(typeof(WechatPayment))]
public partial class PaymentJsonContext : JsonSerializerContext { }
[JsonPolymorphic]
[JsonDerivedType(typeof(CashPayment), "cash")]
[JsonDerivedType(typeof(CreditCardPayment), "credit")]
public abstract class Payment
{
public decimal Amount { get; set; }
public string OrderId { get; set; } = string.Empty;
}
public class CashPayment : Payment { }
public class CreditCardPayment : Payment
{
public string CardNumber { get; set; } = string.Empty;
}依赖注入
AOT 编译要求 DI 注册在编译时完全可解析。动态注册和 ActivatorUtilities.CreateInstance 在 AOT 模式下可能无法正常工作。
// ============================================
// AOT 兼容的 DI 注册方式
// ============================================
var builder = WebApplication.CreateBuilder(args);
// ✅ 标准注册 — AOT 完全兼容
builder.Services.AddSingleton<IUserService, UserService>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddTransient<IEmailService, SmtpEmailService>();
// ✅ 工厂注册 — AOT 兼容
builder.Services.AddSingleton<ICacheProvider>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
return new RedisCacheProvider(config.GetConnectionString("Redis")!);
});
// ✅ 配置绑定 — AOT 兼容
builder.Services.AddOptions<DatabaseOptions>()
.BindConfiguration("Database")
.ValidateDataAnnotations()
.ValidateOnStart();
// ✅ Options 模式 — AOT 兼容(推荐)
public class UserService
{
private readonly DatabaseOptions _options;
// 使用 IOptions<T> 注入配置
public UserService(IOptions<DatabaseOptions> options)
{
_options = options.Value;
}
}
// ✅ 带参数的工厂注册
builder.Services.AddScoped(sp =>
{
var dbContext = sp.GetRequiredService<AppDbContext>();
var logger = sp.GetRequiredService<ILogger<OrderService>>();
return new OrderService(dbContext, logger);
});
// ❌ 避免运行时动态注册
// 以下模式在 AOT 中可能失败:
// builder.Services.AddSingleton(typeof(IGenericService<>), typeof(GenericService<>));
// 当 GenericService<> 内部使用反射时配置绑定
// ============================================
// AOT 兼容的配置模式
// ============================================
// appsettings.json
/*
{
"Database": {
"ConnectionString": "Server=localhost;Database=AppDb;",
"MaxPoolSize": 100,
"CommandTimeout": 30
},
"Cache": {
"Provider": "Redis",
"ExpirationMinutes": 30
}
}
*/
// 定义配置类(使用 DataAnnotations 验证)
public class DatabaseOptions
{
[Required]
public string ConnectionString { get; set; } = string.Empty;
[Range(1, 1000)]
public int MaxPoolSize { get; set; } = 100;
[Range(1, 300)]
public int CommandTimeout { get; set; } = 30;
}
public class CacheOptions
{
[Required]
public string Provider { get; set; } = "InMemory";
[Range(1, 1440)]
public int ExpirationMinutes { get; set; } = 30;
}
// 注册配置
builder.Services.AddOptions<DatabaseOptions>()
.BindConfiguration("Database")
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddOptions<CacheOptions>()
.BindConfiguration("Cache")
.ValidateDataAnnotations()
.ValidateOnStart();
// 在服务中使用
public class OrderService
{
private readonly DatabaseOptions _dbOptions;
private readonly CacheOptions _cacheOptions;
public OrderService(
IOptions<DatabaseOptions> dbOptions,
IOptions<CacheOptions> cacheOptions)
{
_dbOptions = dbOptions.Value;
_cacheOptions = cacheOptions.Value;
}
}兼容性处理
AOT 不兼容的模式及替代方案
// ============================================
// 1. 反射创建实例
// ============================================
// ❌ 不兼容 — 使用 Activator.CreateInstance
var type = Type.GetType("MyApp.Models.User");
var instance = Activator.CreateInstance(type)!;
// ✅ 替代方案 A — 工厂模式(推荐)
public static class ModelFactory
{
private static readonly Dictionary<string, Func<object>> Factories = new()
{
["User"] = () => new User(),
["Order"] = () => new Order(),
["Product"] = () => new Product()
};
public static T Create<T>(string typeName) where T : class
{
return Factories.TryGetValue(typeName, out var factory)
? (T)factory()
: throw new ArgumentException($"Unknown type: {typeName}");
}
}
// ✅ 替代方案 B — switch 表达式
static object CreateModel(string typeName) => typeName switch
{
"User" => new User(),
"Order" => new Order(),
_ => throw new ArgumentException($"Unknown type: {typeName}")
};
// ============================================
// 2. 反射调用方法
// ============================================
// ❌ 不兼容 — 使用 MethodInfo.Invoke
var method = typeof(Processor).GetMethod("Process");
method!.Invoke(instance, new object[] { data });
// ✅ 替代方案 — 委托字典
public class ProcessorFactory
{
private static readonly Dictionary<string, Action<object, object>> Methods = new()
{
["Process"] = (obj, arg) => ((Processor)obj).Process(arg),
["Validate"] = (obj, arg) => ((Validator)obj).Validate(arg)
};
public static void Invoke(string methodName, object instance, object arg)
{
if (Methods.TryGetValue(methodName, out var method))
{
method(instance, arg);
}
}
}
// ============================================
// 3. 动态代码生成
// ============================================
// ❌ 不兼容 — Expression.Lambda 编译
var parameter = Expression.Parameter(typeof(object));
var lambda = Expression.Lambda<Func<object>>(Expression.New(typeof(User)));
var compiled = lambda.Compile();
var user = compiled();
// ❌ 不兼容 — Reflection.Emit
var dynamicMethod = new DynamicMethod("MyMethod", ...);
// ❌ 不兼容 — dynamic 关键字
dynamic obj = JsonConvert.DeserializeObject(json);
obj.SomeProperty;
// ❌ 不兼容 — Assembly.LoadFrom 运行时加载
Assembly.LoadFrom("MyPlugin.dll");
// ============================================
// 4. 正则表达式
// ============================================
// ❌ 不兼容(可能工作但性能差)— 运行时解析正则
var regex = new Regex(@"\d{4}-\d{2}-\d{2}");
// ✅ 替代方案 — [GeneratedRegex](编译时生成)
[GeneratedRegex(@"\d{4}-\d{2}-\d{2}")]
private static partial Regex DateRegex();
[GeneratedRegex(@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")]
private static partial Regex EmailRegex();
[GeneratedRegex(@"^1[3-9]\d{9}$")]
private static partial Regex PhoneRegex();
// 使用
if (DateRegex().IsMatch(input))
{
// 处理日期
}检查第三方库的 AOT 兼容性
# 使用 dotnet publish 的 AOT 分析功能
dotnet publish -c Release -r linux-x64 -p:PublishAot=true 2>&1 | grep "IL2028\|IL3050\|IL2090"
# 常见警告代码:
# IL2028 — 不支持的反射用法
# IL3050 — 调用 RequiresDynamicCodeAttribute 标记的方法
# IL2090 — 调用 RequiresUnreferencedCodeAttribute 标记的方法// 使用 TrimmingAnalysis 属性自定义警告
public class MyService
{
// 标记方法需要动态代码,让编译器跳过检查
[RequiresDynamicCode("This method uses reflection to create instances")]
public object CreateFromType(string typeName)
{
return Type.GetType(typeName) is Type t
? Activator.CreateInstance(t)!
: throw new InvalidOperationException();
}
// 标记方法需要未引用的代码
[RequiresUnreferencedCode("Uses reflection to access properties")]
public Dictionary<string, object> ToDictionary(object obj)
{
return obj.GetType().GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(obj)!);
}
// AOT 安全的替代实现
[UnconditionalSuppressMessage("Trimming", "IL2028")]
public T CreateSafely<T>() where T : new()
{
return new T();
}
}ASP.NET Core AOT 完整示例
Minimal API 完整项目
// Program.cs
using System.Text.Json.Serialization;
// ============================================
// JSON Source Generator
// ============================================
[JsonSerializable(typeof(User))]
[JsonSerializable(typeof(List<User>))]
[JsonSerializable(typeof(CreateUserRequest))]
[JsonSerializable(typeof(ApiResponse<User>))]
[JsonSerializable(typeof(ApiResponse<List<User>>))]
[JsonSerializable(typeof(PagedResult<User>))]
public partial class AppJsonContext : JsonSerializerContext { }
// ============================================
// 数据模型
// ============================================
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
public class CreateUserRequest
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
public class ApiResponse<T>
{
public bool Success { get; set; }
public string? Message { get; set; }
public T? Data { get; set; }
}
public class PagedResult<T>
{
public List<T> Items { get; set; } = new();
public int TotalCount { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
}
// ============================================
// 服务层
// ============================================
public interface IUserService
{
List<User> GetAll();
User? GetById(int id);
User Create(CreateUserRequest request);
}
public class UserService : IUserService
{
private readonly List<User> _users = new();
private int _nextId = 1;
public List<User> GetAll() => _users;
public User? GetById(int id) => _users.FirstOrDefault(u => u.Id == id);
public User Create(CreateUserRequest request)
{
var user = new User
{
Id = _nextId++,
Name = request.Name,
Email = request.Email
};
_users.Add(user);
return user;
}
}
// ============================================
// 配置类
// ============================================
public class AppOptions
{
public const string SectionName = "App";
[Required]
public string AppName { get; set; } = "MyAotApi";
}
// ============================================
// 中间件
// ============================================
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
public RequestLoggingMiddleware(
RequestDelegate next,
ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var start = Stopwatch.GetTimestamp();
await _next(context);
var elapsed = Stopwatch.GetElapsedTime(start);
_logger.LogInformation(
"HTTP {Method} {Path} => {StatusCode} in {ElapsedMs:F2}ms",
context.Request.Method,
context.Request.Path,
context.Response.StatusCode,
elapsed.TotalMilliseconds);
}
}
// ============================================
// 程序入口
// ============================================
var builder = WebApplication.CreateBuilder(args);
// 配置 JSON 序列化
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolver = AppJsonContext.Default;
});
// 注册服务
builder.Services.AddSingleton<IUserService, UserService>();
// 注册配置
builder.Services.AddOptions<AppOptions>()
.BindConfiguration(AppOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
// 健康检查
builder.Services.AddHealthChecks();
var app = builder.Build();
// 自定义中间件
app.UseMiddleware<RequestLoggingMiddleware>();
// 端点路由
app.MapGet("/api/users", (IUserService service) =>
{
var users = service.GetAll();
return new ApiResponse<List<User>>
{
Success = true,
Data = users
};
});
app.MapGet("/api/users/{id:int}", (int id, IUserService service) =>
{
var user = service.GetById(id);
return user is not null
? Results.Ok(new ApiResponse<User> { Success = true, Data = user })
: Results.NotFound(new ApiResponse<User>
{
Success = false,
Message = $"User {id} not found"
});
});
app.MapPost("/api/users", (CreateUserRequest request, IUserService service) =>
{
var user = service.Create(request);
return Results.Created($"/api/users/{user.Id}",
new ApiResponse<User> { Success = true, Data = user });
});
// 健康检查端点
app.MapHealthChecks("/health");
app.Run();发布与优化
发布优化策略
# ============================================
# 开发环境 — 快速迭代
# ============================================
dotnet publish -c Release -r linux-x64
# ============================================
# 生产环境 — 优化体积(适合容器部署)
# ============================================
dotnet publish -c Release -r linux-x64 \
-p:OptimizationPreference=Size \
-p:InvariantGlobalization=true \
-p:PublishAot=true \
-p:StripSymbols=true
# ============================================
# 生产环境 — 优化速度(适合高吞吐场景)
# ============================================
dotnet publish -c Release -r linux-x64 \
-p:OptimizationPreference=Speed \
-p:PublishAot=true \
-p:StripSymbols=false
# ============================================
# Docker 构建优化 — 多阶段构建
# ============================================
# Dockerfile
# FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
# WORKDIR /src
# COPY *.csproj .
# RUN dotnet restore -r linux-musl-x64
# COPY . .
# RUN dotnet publish -c Release -r linux-musl-x64 \
# -p:OptimizationPreference=Size \
# -p:InvariantGlobalization=true \
# -o /app/publish
#
# FROM scratch
# COPY --from=build /app/publish /app
# ENTRYPOINT ["/app/MyAotApi"]性能对比
# 典型 ASP.NET Core Minimal API 对比(单个 JSON 端点)
| 指标 | JIT (.NET 8) | Native AOT | 差异 |
|---------------|---------------|---------------|----------------|
| 启动时间 | ~200ms | ~15ms | 快 13x |
| 内存占用 | ~80MB | ~20MB | 少 75% |
| 发布体积 | ~150MB | ~20MB | 小 87% |
| 首次请求延迟 | ~500ms | ~15ms | 快 33x |
| 稳态吞吐量 | 基准 | 基准 - 2~5% | 基本相当 |
| P99 延迟 | 基准 | 基准 - 3~8% | 略优 |# 更复杂的 API(含 EF Core、认证、中间件)
| 指标 | JIT (.NET 8) | Native AOT |
|---------------|---------------|---------------|
| 冷启动时间 | ~800ms | ~30ms |
| 工作集内存 | ~120MB | ~40MB |
| 镜像大小 | ~200MB | ~30MB |
| 编译时间 | ~10s | ~60-120s |Docker 多阶段构建
# ============================================
# AOT 优化的 Dockerfile
# ============================================
# 构建阶段
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# 先复制项目文件,利用 Docker 缓存层
COPY *.csproj .
RUN dotnet restore -r linux-musl-x64
# 复制源代码并发布
COPY . .
RUN dotnet publish -c Release -r linux-musl-x64 \
-p:OptimizationPreference=Size \
-p:InvariantGlobalization=true \
-p:StripSymbols=true \
-o /app/publish
# 运行阶段 — 使用 scratch 基础镜像(最小体积)
FROM scratch AS runtime
# 设置时区(如果需要)
# COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo
# ENV TZ=Asia/Shanghai
# 复制编译产物
COPY --from=build /app/publish /app
# 设置入口点
ENTRYPOINT ["/app/MyAotApi"]
# 暴露端口
EXPOSE 8080AOT 与 Entity Framework Core
Entity Framework Core 8+ 支持 AOT 编译,但有一些限制:
// ============================================
// EF Core AOT 配置
// ============================================
// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("Default"));
// 启用 AOT 兼容模式
options.UseModel(AppDbContextModel.Instance);
});
// 使用命令生成编译时模型
// dotnet ef dbContext optimize
// 这会生成一个 AppDbContextModel.cs 文件
// 包含编译时确定的实体模型# 生成 EF Core 编译时模型
dotnet ef dbContext optimize \
--output-dir Data/CompiledModels \
--namespace MyProject.Data
# 生成的文件类似:
# [DbContext(typeof(AppDbContext))]
// public partial class AppDbContextModel : RuntimeModel
// {
// static AppDbContextModel()
// {
// var model = new AppDbContextModel();
// // ... 编译时确定的实体映射
// }
// }优点
缺点
总结
Native AOT 适合启动速度敏感的场景:Serverless、CLI 工具、微服务。核心约束:不能使用反射和动态代码生成。JSON 用 Source Generator,正则用 [GeneratedRegex],DI 用标准注册。推荐先在新项目中使用 AOT,老项目迁移需要评估兼容性。迁移路径建议:先启用 IsAotCompatible 检查警告,逐步消除不兼容代码,最后再开启 PublishAot。
关键知识点
- 先分清这个主题位于请求链路、后台任务链路还是基础设施链路。
- 服务端主题通常不只关心功能正确,还关心稳定性、性能和可观测性。
- 任何框架能力都要结合配置、生命周期、异常传播和外部依赖一起看。
- AOT 编译是发布时行为,不影响开发调试,但需要在开发阶段就注意兼容性。
项目落地视角
- 画清请求进入、业务执行、外部调用、日志记录和错误返回的完整路径。
- 为关键链路补齐超时、重试、熔断、追踪和结构化日志。
- 把配置与敏感信息分离,并明确不同环境的差异来源。
- AOT 项目建议从 Minimal API 开始,避免复杂框架的兼容性问题。
常见误区
- 只会堆中间件或组件,不知道它们在链路中的执行顺序。
- 忽略生命周期和线程池、连接池等运行时资源约束。
- 没有监控和测试就对性能或可靠性下结论。
- 以为 AOT 一定能提升吞吐量,实际上稳态吞吐量与 JIT 基本相当。
- 忽略编译时间成本,在 CI/CD 流水线中没有预留足够的编译时间。
- 在 AOT 项目中使用 Newtonsoft.Json(不支持 AOT),应使用 System.Text.Json。
进阶路线
- 继续向运行时行为、可观测性、发布治理和微服务协同深入。
- 把主题和数据库、缓存、消息队列、认证授权联动起来理解。
- 沉淀团队级模板,包括统一异常处理、配置约定和基础设施封装。
- 研究跨平台编译和 CI/CD 矩阵构建(同时生成多平台二进制)。
适用场景
- 当你准备把《Native AOT 原生编译》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合 API 服务、后台任务、实时通信、认证授权和微服务协作场景。
- 当需求开始涉及稳定性、性能、可观测性和发布流程时,这类主题会成为基础设施能力。
- 特别适合 AWS Lambda、Azure Functions、Docker 容器等部署形态。
落地建议
- 先定义请求链路与失败路径,再决定中间件、过滤器、服务边界和依赖方式。
- 为关键链路补日志、指标、追踪、超时与重试策略。
- 环境配置与敏感信息分离,避免把生产参数写死在代码或镜像里。
- 使用
IsAotCompatible在开发阶段提前发现兼容性问题。
排错清单
- 先确认问题发生在路由、模型绑定、中间件、业务层还是基础设施层。
- 检查 DI 生命周期、配置来源、序列化规则和认证上下文。
- 查看线程池、连接池、缓存命中率和外部依赖超时。
- 检查 AOT 警告:
dotnet publish输出中的 IL2028、IL3050、IL2090。 - 检查第三方库是否有
[RequiresDynamicCode]或[RequiresUnreferencedCode]标记。
复盘问题
- 如果把《Native AOT 原生编译》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《Native AOT 原生编译》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《Native AOT 原生编译》最大的收益和代价分别是什么?
