Skip to content

与类似技术对比 ​

🆚 MediatR 与其他相关技术的深度对比


📖 概述 ​

理解 MediatR 在技术生态中的定位,有助于做出正确的架构决策。本章对比 MediatR 与以下技术:

  • 直接调用服务
  • 消息队列(RabbitMQ、Azure Service Bus)
  • 事件聚合器(Prism EventAggregator)
  • 动态代理 AOP(Castle DynamicProxy)

1️⃣ MediatR vs 直接调用服务 ​

代码对比 ​

直接调用 ​

csharp
// 服务接口
public interface IOrderService
{
    Task<OrderResult> CreateOrder(CreateOrderRequest request);
}

// 服务实现
public class OrderService : IOrderService
{
    private readonly IOrderRepository _repo;
    private readonly IPaymentService _paymentService;
    private readonly IEmailService _emailService;
    private readonly ILogger<OrderService> _logger;

    public async Task<OrderResult> CreateOrder(CreateOrderRequest request)
    {
        _logger.LogInformation("Creating order");
        
        var order = await _repo.CreateAsync(request);
        await _paymentService.ProcessAsync(order.Id);
        await _emailService.SendConfirmationAsync(order.CustomerEmail);
        
        return new OrderResult { OrderId = order.Id };
    }
}

// 控制器
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;

    public OrdersController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [HttpPost]
    public async Task<ActionResult<OrderResult>> CreateOrder(CreateOrderRequest request)
    {
        var result = await _orderService.CreateOrder(request);
        return Ok(result);
    }
}

MediatR ​

csharp
// 命令
public class CreateOrderCommand : IRequest<OrderResult>
{
    public string ProductName { get; set; }
    public int Quantity { get; set; }
}

// Handler
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
    private readonly IOrderRepository _repo;
    private readonly IMediator _mediator;

    public async Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken ct)
    {
        var order = await _repo.CreateAsync(request);
        
        // 通过事件解耦
        await _mediator.Publish(new OrderCreatedEvent { OrderId = order.Id }, ct);
        
        return new OrderResult { OrderId = order.Id };
    }
}

// 事件处理器(解耦)
public class SendEmailHandler : INotificationHandler<OrderCreatedEvent>
{
    public async Task Handle(OrderCreatedEvent notification, CancellationToken ct)
    {
        await _emailService.SendAsync(notification.OrderId);
    }
}

public class ProcessPaymentHandler : INotificationHandler<OrderCreatedEvent>
{
    public async Task Handle(OrderCreatedEvent notification, CancellationToken ct)
    {
        await _paymentService.ProcessAsync(notification.OrderId);
    }
}

// 控制器
public class OrdersController : ControllerBase
{
    private readonly IMediator _mediator;

    public OrdersController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public async Task<ActionResult<OrderResult>> CreateOrder(CreateOrderCommand command)
    {
        var result = await _mediator.Send(command);
        return Ok(result);
    }
}

对比分析 ​

维度直接调用MediatR
耦合度高(控制器依赖具体服务)低(只依赖 IMediator)
可扩展性差(修改需改多处)好(开闭原则)
测试难度中(需 Mock 多个服务)低(只需 Mock IMediator)
代码复杂度低中
学习曲线无中等
横切关注点手动处理自动应用(管道行为)
适用场景简单 CRUD复杂业务逻辑

选择建议 ​

✅ 使用直接调用:

  • 简单的 CRUD 操作
  • 小型项目
  • 团队不熟悉中介者模式

✅ 使用 MediatR:

  • 复杂业务逻辑
  • 需要解耦
  • 团队协作的大型项目
  • 需要 CQRS 架构

2️⃣ MediatR vs 消息队列 ​

核心区别 ​

特性MediatR消息队列(RabbitMQ等)
通信范围进程内跨进程/跨服务
持久化❌ 内存中✅ 持久化存储
可靠性低(应用重启丢失)高(消息不丢失)
延迟极低(~100ns)较高(~1-10ms)
吞吐量高(受限于单机)极高(分布式)
复杂性低高
运维成本无需要维护 MQ 集群

使用场景对比 ​

MediatR(进程内) ​

csharp
// 同一应用内的模块间通信
await _mediator.Send(new CreateOrderCommand());
await _mediator.Publish(new OrderCreatedEvent());

适用:

  • ✅ 单体应用内部解耦
  • ✅ 同一进程内的模块通信
  • ✅ 不需要持久化的事件

消息队列(跨服务) ​

csharp
// 微服务间通信
await _rabbitMqPublisher.PublishAsync(new OrderCreatedMessage 
{ 
    OrderId = order.Id,
    Timestamp = DateTime.UtcNow 
});

适用:

  • ✅ 微服务间通信
  • ✅ 需要保证消息不丢失
  • ✅ 异步处理耗时操作
  • ✅ 流量削峰

混合使用 ​

csharp
// 应用内使用 MediatR
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
    private readonly IMediator _mediator;
    private readonly IRabbitMqPublisher _mqPublisher;

    public async Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken ct)
    {
        var order = await _repo.CreateAsync(request);
        
        // 进程内事件(通知其他模块)
        await _mediator.Publish(new OrderCreatedEvent { OrderId = order.Id }, ct);
        
        // 跨服务事件(通知其他微服务)
        await _mqPublisher.PublishAsync(new OrderCreatedMessage 
        { 
            OrderId = order.Id 
        });
        
        return new OrderResult { OrderId = order.Id };
    }
}

优势:

  • ✅ 进程内快速通信(MediatR)
  • ✅ 跨服务可靠通信(消息队列)
  • ✅ 各司其职

3️⃣ MediatR vs 事件聚合器 ​

Prism EventAggregator ​

csharp
// Prism EventAggregator
public class OrderCreatedEvent : PubSubEvent<OrderCreatedEventArgs>
{
}

// 订阅
_eventAggregator.GetEvent<OrderCreatedEvent>().Subscribe(args =>
{
    Console.WriteLine($"Order {args.OrderId} created");
});

// 发布
_eventAggregator.GetEvent<OrderCreatedEvent>().Publish(new OrderCreatedEventArgs 
{ 
    OrderId = orderId 
});

对比 ​

特性MediatRPrism EventAggregator
平台.NET StandardWPF/UWP/Xamarin
类型安全✅ 强类型⚠️ 弱类型
请求/响应✅ 支持❌ 仅发布/订阅
管道行为✅ 支持❌ 不支持
DI 集成✅ 优秀⚠️ 一般
社区活跃度高中
适用场景后端/全栈UI 层事件

选择建议 ​

✅ 使用 MediatR:

  • 后端应用
  • 需要请求/响应模式
  • 需要管道行为

✅ 使用 EventAggregator:

  • WPF/UWP 应用
  • UI 层事件通信
  • 已使用 Prism 框架

4️⃣ MediatR vs 动态代理 AOP ​

Castle DynamicProxy ​

csharp
// 定义拦截器
public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"Before: {invocation.Method.Name}");
        
        try
        {
            invocation.Proceed(); // 执行原方法
            Console.WriteLine($"After: {invocation.Method.Name}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
            throw;
        }
    }
}

// 创建代理
var proxy = generator.CreateInterfaceProxyWithTarget<IOrderService>(
    orderService, 
    new LoggingInterceptor());

// 调用时自动拦截
await proxy.CreateOrder(request); // 自动记录日志

对比 ​

特性MediatR PipelineCastle DynamicProxy
实现方式装饰器模式动态代理
性能开销低(~20ns/behavior)中(~50ns/method)
灵活性高(可条件执行)中(全局拦截)
学习曲线中等陡峭
调试难度低高(代理对象)
适用场景请求级横切关注点方法级横切关注点

选择建议 ​

✅ 使用 MediatR Pipeline:

  • 请求/响应级别的处理
  • 需要灵活的条件逻辑
  • 团队熟悉 MediatR

✅ 使用 DynamicProxy:

  • 方法级别的拦截
  • 已有 Castle 基础设施
  • 需要更细粒度的控制

📊 综合对比矩阵 ​

技术选型决策树 ​

mermaid
graph TD
    A[需要解耦?] -->|否| B[直接调用]
    A -->|是| C{通信范围?}
    
    C -->|进程内| D[MediatR]
    C -->|跨服务| E[消息队列]
    
    D --> F{需要UI事件?}
    F -->|是| G[EventAggregator]
    F -->|否| D
    
    D --> H{需要方法级拦截?}
    H -->|是| I[DynamicProxy]
    H -->|否| D
    
    style D fill:#90EE90
    style E fill:#87CEEB
    style G fill:#FFB6C1
    style I fill:#DDA0DD

场景推荐表 ​

场景首选备选理由
Web API 后端MediatR直接调用成熟、解耦、易测试
微服务通信消息队列MediatR + MQ可靠、分布式
WPF 应用EventAggregatorMediatRUI 事件专用
简单 CRUD直接调用MediatR无需过度设计
方法级拦截DynamicProxyMediatR Pipeline细粒度控制
学习目的MediatR手动实现社区资源多

🎯 最佳实践 ​

组合使用策略 ​

csharp
// 典型企业应用架构
public class OrderController : ControllerBase
{
    private readonly IMediator _mediator; // 进程内解耦

    [HttpPost]
    public async Task<ActionResult> CreateOrder(CreateOrderCommand command)
    {
        // 1. MediatR 处理业务逻辑
        var result = await _mediator.Send(command);
        
        // 2. Handler 内部发布领域事件
        // 3. 事件处理器发送消息到队列(跨服务)
        // 4. UI 层订阅 EventAggregator(如果是桌面应用)
        
        return Ok(result);
    }
}

🎓 总结 ​

核心要点 ​

  1. ✅ MediatR:进程内解耦的首选
  2. ✅ 消息队列:跨服务通信的标配
  3. ✅ EventAggregator:UI 层事件专用
  4. ✅ DynamicProxy:方法级拦截
  5. ✅ 直接调用:简单场景足够

选择原则 ​

✅ 根据通信范围选择:进程内 vs 跨服务
✅ 根据复杂度选择:简单 vs 复杂
✅ 根据团队技能选择:熟悉度很重要
✅ 可以组合使用:不同层次用不同技术


💡 提示: 没有银弹,根据实际情况选择最合适的技术方案!

Released under the CC BY-SA 4.0 License.