You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core后端用泛型设计事件及事件处理器系统?

在ASP.NET Core中实现高性能泛型事件系统

核心解决方案思路

  • 以事件名称(GetEventName返回值)为唯一键,提前构建两个核心映射字典:
    1. 事件名称 → 事件类型(Dictionary<string, Type>):用于无反射快速反序列化JSON payload
    2. 事件名称 → 处理器委托工厂(Dictionary<string, Func<IServiceProvider, Action<IEvent>>>):解决泛型类型擦除问题,直接从DI容器获取处理器并执行
  • 用表达式树提前编译类型转换与处理器调用逻辑,替代运行时反射,保证高吞吐量
  • 自动扫描程序集完成事件处理器的DI注册,无需手动逐个配置

具体实现步骤

1. 保留原有基础定义

保持你已定义的事件与处理器接口,仅补充示例属性方便测试:

internal interface IEvent
{
    public static abstract string GetEventName();
}

public class TestEvent : IEvent
{
    public static string GetEventName() => "test_event";
    public string Message { get; set; } = string.Empty;
}

public interface IEventHandler { }

public interface IEventHandler<TEvent> : IEventHandler where TEvent : IEvent
{
    void HandleEvent(TEvent e);
}

public class TestEventHandler : IEventHandler<TestEvent>
{
    private readonly ILogger<TestEventHandler> _logger;

    // 支持DI构造函数注入
    public TestEventHandler(ILogger<TestEventHandler> logger)
    {
        _logger = logger;
    }

    public void HandleEvent(TestEvent e)
    {
        _logger.LogInformation("处理TestEvent: {Message}", e.Message);
    }
}

2. 构建事件映射与处理器委托工厂

创建静态辅助类,在程序启动时提前扫描并构建所有映射:

public static class EventSystemHelper
{
    // 事件名称到事件类型的映射
    public static readonly Dictionary<string, Type> EventTypeMap = new();
    // 事件名称到处理器委托工厂的映射(从DI获取处理器并返回执行委托)
    public static readonly Dictionary<string, Func<IServiceProvider, Action<IEvent>>> HandlerFactoryMap = new();

    static EventSystemHelper()
    {
        // 扫描所有实现IEvent的非抽象类
        var eventTypes = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a => a.GetTypes())
            .Where(t => typeof(IEvent).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

        foreach (var eventType in eventTypes)
        {
            // 获取静态方法GetEventName的返回值
            var eventName = (string)eventType.GetMethod("GetEventName", BindingFlags.Public | BindingFlags.Static)!
                .Invoke(null, null)!;

            EventTypeMap.Add(eventName, eventType);

            // 构建对应的泛型处理器接口类型
            var handlerInterfaceType = typeof(IEventHandler<>).MakeGenericType(eventType);
            // 扫描所有实现该处理器接口的类
            var handlerTypes = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a => a.GetTypes())
                .Where(t => handlerInterfaceType.IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

            foreach (var handlerType in handlerTypes)
            {
                // 用表达式树编译委托:从DI获取处理器→转换为强类型→调用HandleEvent
                var serviceProviderParam = Expression.Parameter(typeof(IServiceProvider));
                var eventParam = Expression.Parameter(typeof(IEvent));

                // 从DI容器获取处理器实例
                var getHandlerExpr = Expression.Call(serviceProviderParam, nameof(IServiceProvider.GetService), null, Expression.Constant(handlerType));
                // 转换为强类型处理器
                var castHandlerExpr = Expression.Convert(getHandlerExpr, handlerInterfaceType);
                // 转换事件为强类型
                var castEventExpr = Expression.Convert(eventParam, eventType);
                // 调用HandleEvent方法
                var handleMethod = handlerInterfaceType.GetMethod(nameof(IEventHandler<TestEvent>.HandleEvent))!;
                var handleCallExpr = Expression.Call(castHandlerExpr, handleMethod, castEventExpr);

                // 编译为可复用的委托工厂
                var factory = Expression.Lambda<Func<IServiceProvider, Action<IEvent>>>(
                    Expression.Lambda<Action<IEvent>>(handleCallExpr, eventParam),
                    serviceProviderParam
                ).Compile();

                HandlerFactoryMap.Add(eventName, factory);
            }
        }
    }

    // 扩展方法:自动注册所有处理器到DI容器
    public static IServiceCollection AddEventHandlers(this IServiceCollection services)
    {
        var handlerTypes = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a => a.GetTypes())
            .Where(t => typeof(IEventHandler).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

        foreach (var handlerType in handlerTypes)
        {
            services.AddScoped(handlerType);
            // 同时注册对应的泛型接口(可选,方便直接注入特定处理器)
            var interfaceType = handlerType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEventHandler<>));
            if (interfaceType != null)
            {
                services.AddScoped(interfaceType, handlerType);
            }
        }

        return services;
    }
}

3. 实现事件处理执行器

创建服务类封装事件反序列化与处理器调用逻辑:

public interface IEventProcessor
{
    Task ProcessEventAsync(string eventName, string jsonPayload);
}

public class EventProcessor : IEventProcessor
{
    private readonly IServiceProvider _serviceProvider;
    private readonly JsonSerializerOptions _jsonOptions;

    public EventProcessor(IServiceProvider serviceProvider, JsonSerializerOptions jsonOptions)
    {
        _serviceProvider = serviceProvider;
        _jsonOptions = jsonOptions;
    }

    public async Task ProcessEventAsync(string eventName, string jsonPayload)
    {
        if (!EventSystemHelper.EventTypeMap.TryGetValue(eventName, out var eventType))
        {
            throw new ArgumentException($"未知事件类型: {eventName}");
        }

        if (!EventSystemHelper.HandlerFactoryMap.TryGetValue(eventName, out var handlerFactory))
        {
            throw new ArgumentException($"未找到事件{eventName}的处理器");
        }

        // 直接指定类型反序列化,无反射开销
        var @event = JsonSerializer.Deserialize(jsonPayload, eventType, _jsonOptions) as IEvent;
        if (@event == null)
        {
            throw new InvalidOperationException($"事件{eventName}反序列化失败");
        }

        // 创建作用域(适配Scoped生命周期的处理器)
        using var scope = _serviceProvider.CreateScope();
        var handleAction = handlerFactory(scope.ServiceProvider);

        // 执行处理器(如需异步可修改接口为HandleEventAsync)
        handleAction(@event);

        await Task.CompletedTask;
    }
}

4. 集成到ASP.NET Core

在Program.cs中完成服务注册与端点配置:

var builder = WebApplication.CreateBuilder(args);

// 自动注册所有事件处理器
builder.Services.AddEventHandlers();

// 注册事件处理执行器
builder.Services.AddSingleton<IEventProcessor, EventProcessor>();

// 注册自定义JSON配置(可选)
builder.Services.AddSingleton<JsonSerializerOptions>(new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    PropertyNameCaseInsensitive = true
});

var app = builder.Build();

// 示例API端点:接收外部事件请求
app.MapPost("/events", async (HttpContext context, IEventProcessor eventProcessor) =>
{
    var request = await JsonSerializer.DeserializeAsync<EventRequest>(context.Request.Body);
    if (request == null)
    {
        return Results.BadRequest("无效请求");
    }

    try
    {
        await eventProcessor.ProcessEventAsync(request.EventName, request.JsonPayload);
        return Results.Ok();
    }
    catch (Exception ex)
    {
        return Results.BadRequest(ex.Message);
    }
});

app.Run();

// 事件请求DTO
public class EventRequest
{
    public string EventName { get; set; } = string.Empty;
    public string JsonPayload { get; set; } = string.Empty;
}

关键优势

  • 高性能:所有映射与委托在启动时提前编译,运行时无反射操作,满足高吞吐量需求
  • 类型安全:编译时校验处理器与事件的匹配关系,运行时转换由表达式树保证正确性
  • DI友好:完全适配ASP.NET Core依赖注入体系,支持处理器构造函数注入任意服务
  • 自动注册:无需手动配置每个处理器,启动时自动扫描程序集完成注册

内容的提问来源于stack exchange,提问作者idchlife

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:35:20