MediatR (两种模式) 使用示例以及区别
MediatR 是一个开源的.NET库,用于实现中介者模式,帮助开发者在应用程序中实现低耦合的通信。它主要用于实现命令查询责任分离(CQRS)模式,这意味着将应用程序中的读操作(查询)与写操作(命令)明确分离。通过MediatR,开发者可以将请求的发送者和请求的处理者解耦,提高代码的可维护性和可测试性。
在使用MediatR时,开发者定义请求(命令或查询)和对应的处理器。当请求被发送时,MediatR负责将其路由到正确的处理器上。这个过程是通过依赖注入(DI)容器自动完成的,无需手动编写大量的路由逻辑。
MediatR支持同步和异步请求处理,也支持发布/订阅模式,使得开发者可以轻松地在应用程序中实现事件驱动的架构。
简单来说,MediatR通过提供一个中央位置来处理所有的请求和消息,帮助开发者构建出更清晰、更易于管理的应用程序架构。
1. CQRS(发送命令模式)模式使用示例
//创建命令
public class CreateUserCommand : IRequest<bool> // 返回类型为bool,表示操作成功与否
{
public string UserName { get; set; }
public string Email { get; set; }
public CreateUserCommand(string userName, string email)
{
UserName = userName;
Email = email;
}
}
//实现具体处理
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, bool>
{
private readonly ILogger<CreateUserCommandHandler> _logger;
public CreateUserCommandHandler(ILogger<CreateUserCommandHandler> logger)
{
_logger = logger;
}
public async Task<bool> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
// 在这里实现创建用户的逻辑
// 假设我们直接返回true表示用户创建成功
_logger.LogInformation($"用户: {request.UserName} 创建成功");
return await Task.FromResult(true);
}
}
//依赖注入注册MediatR
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
});
//使用示例
public class SendUserCommandWorker : BackgroundService
{
private readonly IMediator _mediator;
public SendUserCommandWorker(IMediator mediator)
{
_mediator = mediator;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var command = new CreateUserCommand("张三", "test@example.com");
await _mediator.Send(command);
}
}
2. 发布/订阅模式使用示例
//创建事件
public class UserCreatedEvent : INotification
{
public string UserName { get; }
public UserCreatedEvent(string userName)
{
UserName = userName;
}
}
//实现具体处理
public class EmailNotificationHandler : INotificationHandler<UserCreatedEvent>
{
public Task Handle(UserCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"Sending email to {notification.UserName}.");
// 在这里实现发送邮件的逻辑
return Task.CompletedTask;
}
}
public class LogNotificationHandler : INotificationHandler<UserCreatedEvent>
{
public Task Handle(UserCreatedEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"Logging user creation: {notification.UserName}.");
// 在这里实现日志记录的逻辑
return Task.CompletedTask;
}
}
//依赖注入注册MediatR
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
});
//使用示例
public class SendUserCommandWorker : BackgroundService
{
private readonly IMediator _mediator;
public SendUserCommandWorker(IMediator mediator)
{
_mediator = mediator;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _mediator.Publish(new UserCreatedEvent("张三"));
}
}
注意: 两种模式的区分
发布/订阅模式和发送命令模式是两种不同的通信机制,它们在MediatR库中被用来解决不同的问题。理解它们之间的区别有助于明确何时使用哪一种模式。
发布/订阅模式
- 定义:在发布/订阅模式中,当某个事件发生时,发布者会发布一个事件,所有订阅了这个事件的处理器都会被通知并执行相应的操作。这是一种一对多的通信方式。
- 用例:这种模式通常用于那些需要多个系统或组件响应同一事件的场景。例如,在用户创建成功后,你可能需要发送欢迎邮件、更新统计数据、通知其他系统等,每一项操作都可以通过订阅用户创建事件来实现。
- 示例:
await _mediator.Publish(new UserCreatedEvent(count.ToString()));
在这个例子中,UserCreatedEvent
事件被发布,所有订阅了这个事件的处理器都会执行。
发送命令模式
- 定义:发送命令模式是一种一对一的通信方式,请求发送者发送一个命令,寻找一个对应的处理器来处理这个命令。
- 用例:这种模式适用于执行具体的操作或更改,通常这些操作或更改是单一的、明确的。比如,创建一个用户、更新一个订单等。
- 示例:
await _mediator.Send(command);
在这个例子中,CreateUserCommand
命令被发送,MediatR找到对应的处理器来执行这个命令。
为何要区分?
- 解耦合:通过区分这两种模式,MediatR帮助进一步降低系统内部的耦合度。不同的场景需要不同的解耦策略,明确区分这两种模式可以让设计更加清晰。
- 明确意图:发布/订阅模式和发送命令模式从语义上表达了开发者的不同意图:前者是通知一个事件发生了,后者是请求执行一个具体操作。
- 灵活性:在实际应用中,同一个操作可能既需要执行具体的命令,也需要通知其他组件。区分这两种模式使得开发者可以根据场景灵活选择,或者同时使用这两种模式。
总之,通过区分发布/订阅模式和发送命令模式,MediatR提供了一种灵活而强大的方式来构建应用程序的内部通信,使得代码更加模块化、易于维护和扩展。