mcpField
D
dotnet-aot-architecture

dotnet-aot-architecture

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

关于 dotnet-aot-architecture

dotnet-aot-architecture 为 .NET 8+ 应用提供面向 AOT 的架构设计模式,适用于构建控制台、ASP.NET Core Minimal API 和 worker 服务的开发者。重点是以源生成、显式 DI、AOT 安全序列化和工厂模式替代依赖运行时反射的做法。

主要功能

  1. 01以源生成替代运行时反射
  2. 02采用显式依赖注入注册
  3. 03选择 AOT 安全序列化方案
  4. 04用工厂模式替代 Activator.CreateInstance
  5. 05评估库的 AOT 兼容性

适用场景

  1. 01设计适用于 AOT 的 .NET 8+ 应用
  2. 02将反射式依赖注入改为显式注册
  3. 03为序列化配置源生成
  4. 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 包之前:

  1. 检查包源码中是否有 IsAotCompatible —— 设置了此属性的包已通过 AOT 分析器验证
  2. 检查是否有 [RequiresDynamicCode] / [RequiresUnreferencedCode] 注解 —— 这些注解表示相关 API 与 AOT 不兼容
  3. 针对你的用法运行 AOT 分析器 —— dotnet build /p:EnableAotAnalyzer=true
  4. 检查包的 GitHub Issues 中关于 AOT/裁剪的问题 —— 搜索“Native AOT”、“trimming”、“IL2026”、“IL3050”
  5. 寻找源生成的替代方案 —— 许多基于反射的库现在都有配套的源生成版本
常见库状态
库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 注意事项

  1. 不要在 AOT 项目中使用 Activator.CreateInstance。 它需要运行时反射,而 AOT 不支持此功能。请改用工厂模式、DI 键控服务或 switch 表达式。
  2. 不要使用程序集扫描进行 DI 注册(Scan、RegisterAssemblyTypes、FromAssemblyOf)。这些方法会使用反射在运行时发现类型。请显式注册服务。
  3. 不要在 AOT 中使用 System.Text.Json,但不提供 [JsonSerializable] 上下文。 如果没有源生成的上下文,STJ 会回退到反射,并在运行时失败。
  4. 不要在未经测试的情况下假定某个库与 AOT 兼容。 运行 dotnet build /p:EnableAotAnalyzer=true,并检查针对特定用法的 IL3050/IL2026 警告。
  5. 不要使用 Type.GetType() 或 Assembly.GetTypes() 进行运行时发现。 这些方法依赖可能被裁剪的元数据。请使用编译时已知的类型。

参考资料

评论

支持 Markdown