MediatR 概述
🎯 理解 MediatR 是什么、为什么需要它,以及它能解决什么问题
📖 什么是 MediatR?
MediatR 是一个简单但功能强大的 .NET 中介者模式实现库,由知名开发者 Jimmy Bogard(也是 AutoMapper 的作者)开发和维护。它的核心理念是通过中介者模式来实现应用程序组件之间的解耦和进程内消息传递。
核心定义
MediatR = Mediator Pattern + In-Process Messaging它是一个轻量级的库,专注于一个目标:在应用程序内部实现优雅的消息传递机制。
🏗️ 中介者模式简介
什么是中介者模式?
中介者模式(Mediator Pattern)是一种行为设计模式,它定义了一个中介对象来封装一系列对象之间的交互方式。通过引入中介者,各个对象不需要直接相互引用,从而降低了耦合度。
传统交互 vs 中介者模式
❌ 传统交互(紧耦合)
graph LR
A[对象A] --> B[对象B]
A --> C[对象C]
B --> C
B --> D[对象D]
C --> D
C --> A
D --> A问题:
- 对象之间相互依赖,形成网状结构
- 修改一个对象可能影响多个其他对象
- 难以测试和维护
- 违反单一职责原则
✅ 中介者模式(松耦合)
graph TB
A[对象A] --> M[中介者]
B[对象B] --> M
C[对象C] --> M
D[对象D] --> M
M --> A
M --> B
M --> C
M --> D优势:
- 对象只依赖中介者,不直接依赖其他对象
- 交互逻辑集中在中介者中
- 易于扩展和维护
- 符合单一职责原则和开闭原则
🎯 MediatR 解决了什么问题?
1. 组件解耦
问题场景:在传统三层架构中,控制器直接调用服务层,服务层之间相互调用,导致紧密耦合。
// ❌ 紧耦合示例
public class OrderController : ControllerBase
{
private readonly OrderService _orderService;
private readonly PaymentService _paymentService;
private readonly EmailService _emailService;
private readonly InventoryService _inventoryService;
private readonly AuditService _auditService;
public OrderController(
OrderService orderService,
PaymentService paymentService,
EmailService emailService,
InventoryService inventoryService,
AuditService auditService)
{
_orderService = orderService;
_paymentService = paymentService;
_emailService = emailService;
_inventoryService = inventoryService;
_auditService = auditService;
}
[HttpPost]
public async Task<IActionResult> CreateOrder(OrderRequest request)
{
// 控制器需要协调多个服务
var order = await _orderService.CreateOrder(request);
await _paymentService.ProcessPayment(order);
await _inventoryService.UpdateStock(order);
await _emailService.SendConfirmation(order);
await _auditService.LogAction(order);
return Ok(order);
}
}解决方案:使用 MediatR 实现请求/响应模式
// ✅ 松耦合示例
public class OrderController : ControllerBase
{
private readonly IMediator _mediator;
// 只依赖一个 IMediator
public OrderController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderCommand command)
{
// 发送命令,不关心谁处理、如何处理
var result = await _mediator.Send(command);
return Ok(result);
}
}
// 处理器负责协调各个服务
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
private readonly IOrderRepository _orderRepo;
private readonly IPaymentService _paymentService;
private readonly IInventoryService _inventoryService;
private readonly IEmailService _emailService;
public async Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken ct)
{
// 业务逻辑集中在这里
var order = await _orderRepo.CreateAsync(request.ToOrder());
await _paymentService.ProcessAsync(order.Id);
await _inventoryService.ReserveAsync(order.Items);
await _emailService.SendConfirmationAsync(order.CustomerEmail);
return new OrderResult { OrderId = order.Id };
}
}优势:
- 控制器只负责 HTTP 层面,不包含业务逻辑
- 业务逻辑封装在 Handler 中
- 易于测试和复用
2. 横切关注点分离(AOP)
问题场景:日志、验证、事务、缓存等横切关注点分散在各个方法中,代码重复且难以维护。
// ❌ 横切关注点混杂在业务逻辑中
public class OrderService
{
public async Task<Order> CreateOrder(OrderRequest request)
{
// 日志记录
_logger.LogInformation("开始创建订单: {ProductId}", request.ProductId);
try
{
// 参数验证
if (request.Quantity <= 0)
throw new ArgumentException("数量必须大于0");
// 开启事务
using var transaction = await _dbContext.Database.BeginTransactionAsync();
// 业务逻辑
var order = new Order { /* ... */ };
await _dbContext.Orders.AddAsync(order);
await _dbContext.SaveChangesAsync();
// 提交事务
await transaction.CommitAsync();
_logger.LogInformation("订单创建成功: {OrderId}", order.Id);
return order;
}
catch (Exception ex)
{
_logger.LogError(ex, "订单创建失败");
throw;
}
}
}解决方案:使用 MediatR 管道行为(Pipeline Behaviors)
// ✅ 业务逻辑纯粹,横切关注点通过管道行为处理
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Order>
{
public async Task<Order> Handle(CreateOrderCommand request, CancellationToken ct)
{
// 只关注业务逻辑
var order = new Order
{
ProductId = request.ProductId,
Quantity = request.Quantity
};
await _dbContext.Orders.AddAsync(order);
await _dbContext.SaveChangesAsync(ct);
return order;
}
}
// 日志行为 - 自动应用于所有请求
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
{
_logger.LogInformation("处理请求: {RequestName}", typeof(TRequest).Name);
return await next();
}
}
// 验证行为 - 自动验证所有请求
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
{
var validationResult = await _validator.ValidateAsync(request);
if (!validationResult.IsValid)
throw new ValidationException(validationResult.Errors);
return await next();
}
}
// 事务行为 - 自动管理事务
public class TransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
{
using var transaction = await _dbContext.Database.BeginTransactionAsync(ct);
try
{
var response = await next();
await transaction.CommitAsync(ct);
return response;
}
catch
{
await transaction.RollbackAsync(ct);
throw;
}
}
}优势:
- 业务逻辑纯净,不包含基础设施代码
- 横切关注点统一管理,易于维护
- 可以灵活组合不同的行为
3. 一对多通信(发布/订阅)
问题场景:一个事件触发后,需要执行多个操作(发邮件、更新缓存、写日志等),传统方式需要硬编码调用所有处理器。
// ❌ 硬编码多个处理器调用
public class OrderService
{
private readonly EmailService _emailService;
private readonly CacheService _cacheService;
private readonly AuditService _auditService;
private readonly AnalyticsService _analyticsService;
public async Task CreateOrder(Order order)
{
// 保存订单
await _dbContext.Orders.AddAsync(order);
// 硬编码调用所有相关服务
await _emailService.SendConfirmation(order.CustomerEmail);
await _cacheService.InvalidateAsync($"order_{order.Id}");
await _auditService.LogOrderCreated(order);
await _analyticsService.TrackEvent("order_created", order);
// 每增加一个新需求,都要修改这里
}
}解决方案:使用 MediatR 通知(Notification)实现发布/订阅
// ✅ 发布/订阅模式
public class OrderCreatedNotification : INotification
{
public Guid OrderId { get; set; }
public string CustomerEmail { get; set; }
}
// 处理器 1:发送邮件
public class SendEmailHandler : INotificationHandler<OrderCreatedNotification>
{
public async Task Handle(OrderCreatedNotification notification, CancellationToken ct)
{
await _emailService.SendAsync(notification.CustomerEmail);
}
}
// 处理器 2:更新缓存
public class UpdateCacheHandler : INotificationHandler<OrderCreatedNotification>
{
public async Task Handle(OrderCreatedNotification notification, CancellationToken ct)
{
await _cacheService.InvalidateAsync($"order_{notification.OrderId}");
}
}
// 处理器 3:写审计日志
public class AuditLogHandler : INotificationHandler<OrderCreatedNotification>
{
public async Task Handle(OrderCreatedNotification notification, CancellationToken ct)
{
await _auditService.LogAsync(notification.OrderId);
}
}
// 发布者:只负责发布事件,不关心谁处理
public class OrderService
{
private readonly IMediator _mediator;
public async Task CreateOrder(Order order)
{
await _dbContext.Orders.AddAsync(order);
// 发布通知,所有订阅者自动接收
await _mediator.Publish(new OrderCreatedNotification
{
OrderId = order.Id,
CustomerEmail = order.CustomerEmail
});
}
}优势:
- 发布者和订阅者完全解耦
- 新增处理器无需修改发布者代码(符合开闭原则)
- 每个处理器独立开发和测试
4. CQRS 架构支持
问题场景:读写操作使用相同的数据模型和服务,导致性能瓶颈和复杂性增加。
解决方案:使用 MediatR 实现 CQRS(命令查询职责分离)
// 命令(写操作)
public class CreateOrderCommand : IRequest<OrderResult>
{
public string ProductName { get; set; }
public int Quantity { get; set; }
}
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
public async Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken ct)
{
// 写操作:使用领域模型,保证数据一致性
var order = new Order(request.ProductName, request.Quantity);
await _dbContext.Orders.AddAsync(order);
await _dbContext.SaveChangesAsync(ct);
return new OrderResult { OrderId = order.Id };
}
}
// 查询(读操作)
public class GetOrderQuery : IRequest<OrderDto>
{
public Guid OrderId { get; set; }
}
public class GetOrderHandler : IRequestHandler<GetOrderQuery, OrderDto>
{
public async Task<OrderDto> Handle(GetOrderQuery request, CancellationToken ct)
{
// 读操作:直接使用 DTO,优化查询性能
return await _dbContext.Orders
.Where(o => o.Id == request.OrderId)
.Select(o => new OrderDto
{
Id = o.Id,
ProductName = o.ProductName,
TotalAmount = o.Quantity * o.Price
})
.FirstOrDefaultAsync(ct);
}
}优势:
- 读写模型分离,各自优化
- 可以使用不同的数据库(写用 SQL,读用 NoSQL)
- 提高系统可扩展性
📜 发展历史与版本演进
版本时间线
| 版本 | 发布时间 | 主要特性 |
|---|---|---|
| v1.0 | 2015 | 初始版本,支持请求/响应和通知 |
| v2.0 | 2016 | 添加管道行为(Pipeline Behaviors) |
| v3.0 | 2017 | 改进 API,支持流式处理 |
| v4.0 | 2018 | 性能优化,简化注册 |
| v5.0 | 2019 | 支持 ISender 和 IPublisher 接口分离 |
| v6.0 | 2020 | 改进泛型约束,更好的类型推断 |
| v7.0 | 2021 | 增强 ASP.NET Core 集成 |
| v8.0 | 2021 | 性能优化,减少内存分配 |
| v9.0 | 2022 | 改进错误处理和诊断 |
| v10.0 | 2022 | 支持 .NET 6,最小 API |
| v11.0 | 2023 | 增强源生成器支持 |
| v12.0 | 2023 | 最新稳定版,全面优化 |
| v14.0+ | 2024+ | 编译时源生成器(预览) |
关键里程碑
- 2015:Jimmy Bogard 发布 MediatR 1.0
- 2016:引入管道行为,成为最强大特性
- 2019:GitHub Stars 突破 5,000
- 2021:成为 .NET 生态中最流行的中介者库
- 2023:GitHub Stars 突破 10,000
- 2024:引入源生成器,性能提升 50%+
✅ 适用场景
1. 复杂业务逻辑的应用程序
- ✅ 电商系统(订单、支付、库存)
- ✅ 金融系统(交易、风控、审计)
- ✅ ERP 系统(采购、销售、仓储)
- ✅ CRM 系统(客户、线索、商机)
原因:这些系统业务逻辑复杂,需要良好的解耦和可维护性。
2. 需要 CQRS 架构的项目
- ✅ 读写比例悬殊的系统(如社交网络)
- ✅ 需要不同读写模型的场景
- ✅ 需要最终一致性的分布式系统
原因:MediatR 天然支持命令和查询分离。
3. 团队协作的大型项目
- ✅ 多团队并行开发
- ✅ 需要统一代码规范
- ✅ 频繁的代码审查和重构
原因:统一的模式降低沟通成本,提高代码质量。
4. 领域驱动设计(DDD)项目
- ✅ 需要实现领域事件
- ✅ 需要聚合根和值对象
- ✅ 需要限界上下文
原因:MediatR 的通知机制完美契合领域事件。
❌ 不适用场景
1. 简单的 CRUD 应用
// ❌ 过度设计:简单的增删改查不需要 MediatR
public class UserController : ControllerBase
{
private readonly IMediator _mediator;
[HttpGet("{id}")]
public async Task<User> Get(Guid id)
{
return await _mediator.Send(new GetUserQuery { Id = id });
}
}
// ✅ 直接调用更简单
public class UserController : ControllerBase
{
private readonly IUserRepository _userRepository;
[HttpGet("{id}")]
public async Task<User> Get(Guid id)
{
return await _userRepository.GetByIdAsync(id);
}
}原因:引入 MediatR 会增加不必要的复杂度。
2. 性能极度敏感的系统
- ❌ 高频交易系统
- ❌ 实时游戏服务器
- ❌ 超低延迟 API
原因:虽然 MediatR 性能很好,但仍有少量开销(反射、委托调用)。对于纳秒级要求的系统,直接调用更高效。
3. 小型个人项目
原因:学习成本和配置开销可能超过收益。
4. 跨服务通信
// ❌ MediatR 不支持跨进程通信
await _mediator.Send(new CreateOrderCommand()); // 只能在同一进程中
// ✅ 使用消息队列
await _rabbitMQPublisher.PublishAsync(new CreateOrderMessage()); // 跨服务原因:MediatR 是进程内消息传递,不适用于微服务间通信。应使用 RabbitMQ、Azure Service Bus 等消息队列。
🆚 与其他方案对比
| 特性 | MediatR | 直接调用 | 消息队列 |
|---|---|---|---|
| 耦合度 | 低 | 高 | 最低 |
| 性能 | 中 | 高 | 低 |
| 复杂度 | 中 | 低 | 高 |
| 适用场景 | 进程内解耦 | 简单场景 | 跨服务通信 |
| 学习曲线 | 中等 | 无 | 陡峭 |
| 测试友好度 | ✅ 优秀 | ⚠️ 一般 | ⚠️ 一般 |
💡 核心价值总结
MediatR 的三大核心价值
解耦(Decoupling)
- 组件之间不直接依赖
- 通过消息进行通信
- 易于替换和扩展
单一职责(Single Responsibility)
- 每个 Handler 只处理一种请求
- 管道行为处理横切关注点
- 代码清晰易维护
可测试性(Testability)
- Handler 是纯函数,易于单元测试
- 可以 Mock IMediator
- 隔离测试业务逻辑
🎓 下一步学习
现在你已经了解了 MediatR 是什么以及它能解决什么问题,接下来:
📚 参考资源
- 官方 GitHub: https://github.com/jbogard/MediatR
- 作者博客: https://jimmybogard.com/
- NuGet 包: https://www.nuget.org/packages/MediatR
- Wiki 文档: https://github.com/jbogard/MediatR/wiki
💡 提示:理解 MediatR 的核心价值比记住 API 更重要。在实际项目中,要根据场景判断是否适合使用 MediatR,避免过度设计。