如何将现有事件/通知及处理器适配到MediatR,无需额外实现?
适配现有事件系统到MediatR的方案
这问题我之前帮团队落地过类似的需求,核心是靠MediatR的开放泛型支持和适配器模式,完全不用给每种现有事件/处理器额外写重复代码。咱们一步步来:
先对齐现有结构(先明确上下文)
假设你的现有代码大概是这样的(如果和实际有出入,调整下泛型约束就行):
// 现有事件标记接口 public interface IEvent { } // 现有处理器接口 public interface IEventHandler<TEvent> where TEvent : IEvent { void Handle(TEvent @event); // 如果是异步逻辑就是 Task Handle(TEvent @event); } // 具体事件示例 public class OrderCreatedEvent : IEvent { public Guid OrderId { get; set; } } // 对应的现有处理器 public class OrderCreatedHandler : IEventHandler<OrderCreatedEvent> { public void Handle(OrderCreatedEvent @event) { // 原有处理逻辑 Console.WriteLine($"处理订单创建事件:{@event.OrderId}"); } }
步骤1:创建MediatR通知适配器
把你的IEvent包装成MediatR能识别的INotification类型,用泛型适配器统一处理:
// 泛型适配器,将任意IEvent转换为MediatR的INotification public class EventNotificationAdapter<TEvent> : INotification where TEvent : IEvent { public TEvent Event { get; } public EventNotificationAdapter(TEvent @event) { Event = @event; } }
步骤2:创建通用处理器适配器
把现有IEventHandler<T>适配成MediatR的INotificationHandler<EventNotificationAdapter<T>>,这样所有现有处理器都能被MediatR调用:
// 同步版本适配器 public class EventHandlerAdapter<TEvent> : INotificationHandler<EventNotificationAdapter<TEvent>> where TEvent : IEvent { private readonly IEventHandler<TEvent> _existingHandler; // 通过依赖注入拿到现有处理器 public EventHandlerAdapter(IEventHandler<TEvent> existingHandler) { _existingHandler = existingHandler; } public Task Handle(EventNotificationAdapter<TEvent> notification, CancellationToken cancellationToken) { // 调用现有处理器的Handle方法 _existingHandler.Handle(notification.Event); return Task.CompletedTask; } } // 如果你的现有处理器是异步的,就用这个版本: // public class AsyncEventHandlerAdapter<TEvent> : INotificationHandler<EventNotificationAdapter<TEvent>> // where TEvent : IEvent // { // private readonly IEventHandler<TEvent> _existingHandler; // // public AsyncEventHandlerAdapter(IEventHandler<TEvent> existingHandler) // { // _existingHandler = existingHandler; // } // // public Task Handle(EventNotificationAdapter<TEvent> notification, CancellationToken cancellationToken) // { // return _existingHandler.Handle(notification.Event, cancellationToken); // } // }
步骤3:依赖注入注册关键类型
不管你用的是Microsoft原生DI还是Autofac,核心是注册开放泛型,让容器自动为每个IEvent类型匹配对应的适配器:
原生DI示例
services.AddMediatR(cfg => { // 扫描注册所有现有处理器(指定包含处理器的程序集即可) cfg.RegisterServicesFromAssemblyContaining<OrderCreatedHandler>(); }); // 注册通用处理器适配器(开放泛型) services.AddScoped(typeof(INotificationHandler<>), typeof(EventHandlerAdapter<>));
Autofac示例
builder.RegisterAssemblyTypes(typeof(OrderCreatedHandler).Assembly) .AsClosedTypesOf(typeof(IEventHandler<>)); builder.RegisterGeneric(typeof(EventHandlerAdapter<>)) .As(typeof(INotificationHandler<>)) .InstancePerLifetimeScope(); builder.RegisterMediatR(typeof(Program).Assembly);
步骤4:分发事件到MediatR
现在你只需要把原有IEvent包装成适配器,然后用MediatR的IPublisher发布即可:
public class EventDispatcher { private readonly IPublisher _mediatorPublisher; // 缓存泛型适配器类型,避免重复反射开销 private static readonly Dictionary<Type, Type> _adapterTypeCache = new(); public EventDispatcher(IPublisher mediatorPublisher) { _mediatorPublisher = mediatorPublisher; } public async Task PublishEvent(IEvent @event) { var eventType = @event.GetType(); if (!_adapterTypeCache.TryGetValue(eventType, out var adapterType)) { adapterType = typeof(EventNotificationAdapter<>).MakeGenericType(eventType); _adapterTypeCache[eventType] = adapterType; } // 创建适配器实例并发布 var adapter = Activator.CreateInstance(adapterType, @event); await _mediatorPublisher.Publish(adapter, CancellationToken.None); } }
额外注意点
- 如果你的现有事件系统支持多处理器(一个事件对应多个处理器),MediatR天然支持,适配器会自动调用所有匹配的现有处理器。
- 要是需要统一处理异常,可以在适配器里加try/catch,或者利用MediatR的行为管道(Behavior)做全局拦截。
- 反射创建适配器的部分已经加了缓存,避免重复反射的性能损耗,如果有需要还可以用表达式树进一步优化。
内容的提问来源于stack exchange,提问作者Esben Bach
相关产品推荐
相关产品推荐

