关于 dotnet-aot-architecture
dotnet-aot-architecture 为 .NET 8+ 应用提供面向 AOT 的架构设计模式,适用于构建控制台、ASP.NET Core Minimal API 和 worker 服务的开发者。重点是以源生成、显式 DI、AOT 安全序列化和工厂模式替代依赖运行时反射的做法。
主要功能
- 01以源生成替代运行时反射
- 02采用显式依赖注入注册
- 03选择 AOT 安全序列化方案
- 04用工厂模式替代 Activator.CreateInstance
- 05评估库的 AOT 兼容性
适用场景
- 01设计适用于 AOT 的 .NET 8+ 应用
- 02将反射式依赖注入改为显式注册
- 03为序列化配置源生成
- 04检查 NuGet 包的 AOT 兼容性
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-aot-architecture安装后在 Claude Code 中输入/dotnet-aot-architecture确认已加载。
详细介绍
dotnet-aot-architecture
面向 .NET 8+ 的 AOT 优先应用设计模式:优先使用源生成器而非反射、显式 DI 注册而非程序集扫描、选择 AOT 安全的序列化方式、评估库的兼容性,并使用工厂模式替代 Activator.CreateInstance。
**版本假设:**以 .NET 8.0+ 为基线。这些模式适用于所有支持 AOT 的项目类型(控制台、ASP.NET Core Minimal API、工作器服务)。
**范围之外:**Native AOT 发布流程和 MSBuild 配置——请参阅 [skill:dotnet-native-aot]。安全裁剪的库编写和注解——请参阅 [skill:dotnet-trimming]。WASM AOT 编译——请参阅 [skill:dotnet-aot-wasm]。MAUI 专用 AOT——请参阅 [skill:dotnet-maui-aot]。源生成器编写(Roslyn API)——请参阅 [skill:dotnet-csharp-source-generators]。DI 容器内部机制——请参阅 [skill:dotnet-csharp-dependency-injection]。序列化深入内容——请参阅 [skill:dotnet-serialization]。
交叉引用:[skill:dotnet-native-aot] 介绍 AOT 发布流程,[skill:dotnet-trimming] 介绍裁剪注解和库编写,[skill:dotnet-serialization] 介绍序列化模式,[skill:dotnet-csharp-source-generators] 介绍源生成机制,[skill:dotnet-csharp-dependency-injection] 介绍 DI 基础知识,[skill:dotnet-containers] 介绍 runtime-deps 部署,[skill:dotnet-native-interop] 介绍通用 P/Invoke 模式和封送。
使用源生成器替代反射
AOT 的主要支持方式是使用编译时源生成替代运行时反射。源生成器在构建时生成代码,以便 AOT 编译器分析并包含这些代码。
关键的源生成器替代方案
| 反射模式 | 源生成器 / AOT 安全的替代方案 | 库 |
|---|---|---|
JsonSerializer.Deserialize<T>() | [JsonSerializable] 上下文 | System.Text.Json(内置) |
Activator.CreateInstance<T>() | 使用显式 new 的工厂模式 | 手动 |
使用 Type.GetProperties() 进行映射 | [Mapper] 特性 | Mapperly |
Regex 模式编译 | [GeneratedRegex] 特性 | 内置(.NET 7+) |
使用字符串插值的 ILogger.Log(...) | [LoggerMessage] 特性 | Microsoft.Extensions.Logging |
| 为 DI 扫描程序集 | 显式调用 services.Add*() | 手动 |
[DllImport] P/Invoke | [LibraryImport] | 内置(.NET 7+) |
AutoMapper CreateMap<>() | [Mapper] 源生成 | Mapperly |
示例:迁移到源生成
// BEFORE: Reflection-based (breaks under AOT)
var logger = loggerFactory.CreateLogger<OrderService>();
logger.LogInformation("Order {OrderId} created for {Customer}", order.Id, order.CustomerId);
// AFTER: Source-generated (AOT-safe, zero-alloc)
public partial class OrderService
{
[LoggerMessage(Level = LogLevel.Information,
Message = "Order {OrderId} created for {Customer}")]
private static partial void LogOrderCreated(
ILogger logger, int orderId, string customer);
}
// Usage:
LogOrderCreated(_logger, order.Id, order.CustomerId);
有关源生成器机制和编写模式,请参阅 [skill:dotnet-csharp-source-generators]。
AOT 安全的 DI 模式
AOT 中的依赖注入要求显式注册服务。程序集扫描(AddServicesFromAssembly)和开放泛型解析可能需要 AOT 无法满足的反射。
显式注册(推荐)
var builder = WebApplication.CreateSlimBuilder(args);
// Explicit registrations -- AOT-safe
builder.Services.AddSingleton<IOrderRepository, PostgresOrderRepository>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();
builder.Services.AddSingleton(TimeProvider.System);
避免程序集扫描
// BAD: Assembly scanning uses reflection -- breaks under AOT
builder.Services.Scan(scan => scan
.FromAssemblyOf<OrderService>()
.AddClasses(classes => classes.AssignableTo<IService>())
.AsImplementedInterfaces()
.WithScopedLifetime());
// GOOD: Explicit registrations grouped by concern
builder.Services.AddOrderServices();
builder.Services.AddInventoryServices();
// Extension method groups related registrations
public static class OrderServiceExtensions
{
public static IServiceCollection AddOrderServices(
this IServiceCollection services)
{
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IOrderRepository, PostgresOrderRepository>();
services.AddScoped<IOrderValidator, OrderValidator>();
return services;
}
}
键控服务(.NET 8+)
// AOT-safe keyed service registration
builder.Services.AddKeyedSingleton<INotificationSender, EmailSender>("email");
builder.Services.AddKeyedSingleton<INotificationSender, SmsSender>("sms");
// Resolve by key
app.MapPost("/notify", ([FromKeyedServices("email")] INotificationSender sender) =>
sender.SendAsync("Hello"));
有关完整的 DI 模式,请参阅 [skill:dotnet-csharp-dependency-injection]。
AOT 的序列化选择
决策矩阵
| 序列化器 | AOT 安全 | 所需设置 | 适用场景 |
|---|---|---|---|
| System.Text.Json + 源生成 | 是 | [JsonSerializable] 上下文 | API、配置、JSON 互操作 |
| Protobuf(Google.Protobuf) | 是 | .proto 架构文件 | gRPC、服务间通信 |
| MessagePack + 源生成 | 是 | [MessagePackObject] + 源生成解析器 | 缓存、实时场景 |
| Newtonsoft.Json | 否 | 不适用 | 不要用于 AOT |
| 未使用源生成的 STJ | 否 | 不适用 | 会回退到反射 |
STJ 源生成设置
// Define serializable types
[JsonSerializable(typeof(Product))]
[JsonSerializable(typeof(List<Product>))]
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
internal partial class AppJsonContext : JsonSerializerContext { }
// Register in ASP.NET Core
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0,
AppJsonContext.Default);
});
有关全面的序列化模式,请参阅 [skill:dotnet-serialization]。
使用工厂模式替代 Activator.CreateInstance
Activator.CreateInstance 使用运行时反射创建实例,因此与 AOT 不兼容。请改用显式构造实例的工厂模式。
简单工厂
// BAD: Reflection-based creation -- breaks under AOT
public T CreateHandler<T>() where T : class
=> (T)Activator.CreateInstance(typeof(T))!;
// GOOD: Factory with explicit registration
public class HandlerFactory
{
private readonly Dictionary<Type, Func<IHandler>> _factories = new();
public void Register<T>(Func<T> factory) where T : IHandler
=> _factories[typeof(T)] = () => factory();
public IHandler Create<T>() where T : IHandler
=> _factories[typeof(T)]();
}
// Registration
var factory = new HandlerFactory();
factory.Register<OrderHandler>(() => new OrderHandler(repository, logger));
factory.Register<PaymentHandler>(() => new PaymentHandler(gateway));
通过 DI 实现策略模式
// BAD: Dynamic type resolution
public IPaymentProcessor GetProcessor(string type)
{
var processorType = Type.GetType($"MyApp.Payments.{type}Processor");
return (IPaymentProcessor)Activator.CreateInstance(processorType!)!;
}
// GOOD: Keyed services (.NET 8+)
builder.Services.AddKeyedScoped<IPaymentProcessor, CreditCardProcessor>("CreditCard");
builder.Services.AddKeyedScoped<IPaymentProcessor, BankTransferProcessor>("BankTransfer");
builder.Services.AddKeyedScoped<IPaymentProcessor, WalletProcessor>("Wallet");
// Resolve at runtime without reflection
app.MapPost("/pay", (
[FromQuery] string type,
IServiceProvider sp) =>
{
var processor = sp.GetRequiredKeyedService<IPaymentProcessor>(type);
return processor.ProcessAsync();
});
基于枚举的工厂
// For a fixed set of types, use a switch expression
public static IExporter CreateExporter(ExportFormat format) => format switch
{
ExportFormat.Csv => new CsvExporter(),
ExportFormat.Json => new JsonExporter(),
ExportFormat.Pdf => new PdfExporter(),
_ => throw new ArgumentOutOfRangeException(nameof(format))
};
库兼容性评估
评估清单
在 AOT 项目中采用 NuGet 包之前:
- 检查包源码中是否有
IsAotCompatible—— 设置了此属性的包已通过 AOT 分析器验证 - 检查是否有
[RequiresDynamicCode]/[RequiresUnreferencedCode]注解 —— 这些注解表示相关 API 与 AOT 不兼容 - 针对你的用法运行 AOT 分析器 ——
dotnet build /p:EnableAotAnalyzer=true - 检查包的 GitHub Issues 中关于 AOT/裁剪的问题 —— 搜索“Native AOT”、“trimming”、“IL2026”、“IL3050”
- 寻找源生成的替代方案 —— 许多基于反射的库现在都有配套的源生成版本
常见库状态
| 库 | AOT 状态 | AOT 安全的替代方案 |
|---|---|---|
| AutoMapper | 不兼容 | Mapperly |
| MediatR | 部分兼容(显式注册) | 直接调用方法或使用工厂 |
| FluentValidation | 部分兼容 | 手动验证或源生成 |
| Dapper | 兼容(支持 .NET 8+ AOT) | -- |
| Entity Framework Core | 部分兼容(预编译查询) | 对 AOT 密集型路径使用 Dapper |
| Refit | 兼容(7+ 版本支持源生成) | -- |
| Polly | 兼容(v8+) | -- |
| Serilog | 部分兼容 | [LoggerMessage] 源生成 |
| Hangfire | 不兼容 | 自定义 IHostedService |
测试兼容性
# Build with all analyzers enabled
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true /p:TrimmerSingleWarn=false
# Warnings indicate AOT-incompatible usage
# IL3050 = RequiresDynamicCode (definitely breaks)
# IL2026 = RequiresUnreferencedCode (may break)
AOT 应用架构模板
src/
MyApp/
Program.cs # CreateSlimBuilder, explicit DI
MyApp.csproj # PublishAot=true, EnableAotAnalyzer=true
JsonContext.cs # [JsonSerializable] for all API types
Endpoints/
OrderEndpoints.cs # Minimal API route groups
ProductEndpoints.cs
Services/
OrderService.cs # Business logic (no reflection)
IOrderService.cs
Repositories/
OrderRepository.cs # Data access (Dapper or EF precompiled)
Extensions/
ServiceCollectionExtensions.cs # Grouped DI registrations
Agent 注意事项
- 不要在 AOT 项目中使用
Activator.CreateInstance。 它需要运行时反射,而 AOT 不支持此功能。请改用工厂模式、DI 键控服务或 switch 表达式。 - 不要使用程序集扫描进行 DI 注册(
Scan、RegisterAssemblyTypes、FromAssemblyOf)。这些方法会使用反射在运行时发现类型。请显式注册服务。 - 不要在 AOT 中使用
System.Text.Json,但不提供[JsonSerializable]上下文。 如果没有源生成的上下文,STJ 会回退到反射,并在运行时失败。 - 不要在未经测试的情况下假定某个库与 AOT 兼容。 运行
dotnet build /p:EnableAotAnalyzer=true,并检查针对特定用法的 IL3050/IL2026 警告。 - 不要使用
Type.GetType()或Assembly.GetTypes()进行运行时发现。 这些方法依赖可能被裁剪的元数据。请使用编译时已知的类型。