与类似技术对比
🆚 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
});对比
| 特性 | MediatR | Prism EventAggregator |
|---|---|---|
| 平台 | .NET Standard | WPF/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 Pipeline | Castle 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 应用 | EventAggregator | MediatR | UI 事件专用 |
| 简单 CRUD | 直接调用 | MediatR | 无需过度设计 |
| 方法级拦截 | DynamicProxy | MediatR 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);
}
}🎓 总结
核心要点
- ✅ MediatR:进程内解耦的首选
- ✅ 消息队列:跨服务通信的标配
- ✅ EventAggregator:UI 层事件专用
- ✅ DynamicProxy:方法级拦截
- ✅ 直接调用:简单场景足够
选择原则
✅ 根据通信范围选择:进程内 vs 跨服务
✅ 根据复杂度选择:简单 vs 复杂
✅ 根据团队技能选择:熟悉度很重要
✅ 可以组合使用:不同层次用不同技术
💡 提示: 没有银弹,根据实际情况选择最合适的技术方案!