用MediatR打造高内聚低耦合的优雅代码,从此告别“面条式“架构!
set;set;set;✅ 基础搭建 - 初识 MediatR✅ 命令与查询 - CQRS 模式实践✅ 通知与事件 - 发布/订阅模式✅ 管道行为 - 中间件式处理✅ 高级技巧 - 验证、事务等。
🌟 开篇:初识 MediatR
在.NET 的修仙世界中,MediatR 就像是一本神奇的"传音入密"秘籍,它能让你的代码各司其职,却又心意相通。今天,就让我们一起来修炼这本秘籍,掌握.NET 中的中介者模式精髓!
MediatR 是一个简单的中介者模式实现,它通过解耦消息发送者和接收者来简化应用程序中的进程内通信。简单来说,它就像是一个邮局,负责把你的"信件"(消息)准确无误地投递给正确的"收件人"(处理器)。
// 安装MediatR
dotnet add package MediatR
🏗️ 第一重境界:基础搭建
1. 配置 MediatR
首先,我们需要在 Startup.cs 或 Program.cs 中注册 MediatR 服务:
// .NET 6+ 的Program.cs
builder.Services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
2. 创建第一个消息和处理器
让我们从一个简单的"Hello World"开始:
// 定义消息
public class HelloWorldQuery : IRequest<string>
{
public string Name { get; set; }
}
// 定义处理器
public class HelloWorldHandler : IRequestHandler<HelloWorldQuery, string>
{
public Task<string> Handle(HelloWorldQuery request, CancellationToken cancellationToken)
{
return Task.FromResult($"Hello, {request.Name}!");
}
}
// 使用示例
var response = await mediator.Send(new HelloWorldQuery { Name = "修仙者" });
Console.WriteLine(response); // 输出: Hello, 修仙者!
🧩 第二重境界:命令与查询
MediatR 支持两种主要模式:命令(Command)和查询(Query),对应 CQRS 模式。
1. 命令模式示例
// 创建用户命令
public class CreateUserCommand : IRequest<int>
{
public string Username { get; set; }
public string Email { get; set; }
}
public class CreateUserHandler : IRequestHandler<CreateUserCommand, int>
{
private readonly ApplicationDbContext _context;
public CreateUserHandler(ApplicationDbContext context)
{
_context = context;
}
public async Task<int> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
var user = new User
{
Username = request.Username,
Email = request.Email
};
_context.Users.Add(user);
await _context.SaveChangesAsync(cancellationToken);
return user.Id;
}
}
2. 查询模式示例
// 获取用户详情查询
public class GetUserByIdQuery : IRequest<UserDto>
{
public int UserId { get; set; }
}
public class GetUserByIdHandler
: IRequestHandler<GetUserByIdQuery, UserDto>
{
private readonly ApplicationDbContext _context;
public GetUserByIdHandler(ApplicationDbContext context)
{
_context = context;
}
public async Task<UserDto> Handle(
GetUserByIdQuery request,
CancellationToken cancellationToken)
{
var user = await _context.Users
.Where(u => u.Id == request.UserId)
.Select(u => new UserDto
{
Id = u.Id,
Username = u.Username,
Email = u.Email
})
.FirstOrDefaultAsync(cancellationToken);
return user ?? throw new NotFoundException("User not found");
}
}
🔗 第三重境界:通知与事件
MediatR 还支持发布/订阅模式,通过 INotification 接口实现。
1. 定义通知事件
public class UserCreatedNotification : INotification
{
public int UserId { get; set; }
public string Username { get; set; }
public DateTime CreatedAt { get; set; }
}
2. 创建多个处理器
// 发送欢迎邮件处理器
public class SendWelcomeEmailHandler : INotificationHandler<UserCreatedNotification>
{
public async Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
{
// 模拟发送邮件
Console.WriteLine($"发送欢迎邮件给 {notification.Username}");
await Task.Delay(1000);
}
}
// 记录用户创建日志处理器
public class LogUserCreatedHandler : INotificationHandler<UserCreatedNotification>
{
private readonly ILogger<LogUserCreatedHandler> _logger;
public LogUserCreatedHandler(ILogger<LogUserCreatedHandler> logger)
{
_logger = logger;
}
public Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
{
_logger.LogInformation("新用户创建: {UserId}, 用户名: {Username}",
notification.UserId, notification.Username);
return Task.CompletedTask;
}
}
3. 发布通知
await mediator.Publish(new UserCreatedNotification
{
UserId = newUserId,
Username = command.Username,
CreatedAt = DateTime.UtcNow
});
🛡️ 第四重境界:管道行为
MediatR 的管道行为(Pipeline Behaviors)类似于 ASP.NET Core 的中间件,可以在处理请求前后执行逻辑
1. 创建日志行为
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
_logger.LogInformation("处理请求 {RequestName} {@Request}",
typeof(TRequest).Name, request);
try
{
var response = await next();
_logger.LogInformation("请求 {RequestName} 处理成功", typeof(TRequest).Name);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "请求 {RequestName} 处理出错", typeof(TRequest).Name);
throw;
}
}
}
2. 创建验证行为
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var validationResults = await Task.WhenAll(
_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.SelectMany(r => r.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
}
return await next();
}
}
3. 注册行为
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
🎯 第五重境界:高级技巧
1. 使用 FluentValidation 进行验证
public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
{
public CreateUserCommandValidator()
{
RuleFor(x => x.Username)
.NotEmpty().WithMessage("用户名不能为空")
.MinimumLength(3).WithMessage("用户名至少3个字符")
.MaximumLength(20).WithMessage("用户名最多20个字符");
RuleFor(x => x.Email)
.NotEmpty().WithMessage("邮箱不能为空")
.EmailAddress().WithMessage("邮箱格式不正确");
}
}
// 注册验证器
builder.Services.AddValidatorsFromAssemblyContaining<CreateUserCommandValidator>();
2. 使用特性标记处理器
// 自定义特性
[AttributeUsage(AttributeTargets.Class)]
public class TransactionalAttribute : Attribute
{
}
// 创建事务行为
public class TransactionalBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly ApplicationDbContext _context;
public TransactionalBehavior(ApplicationDbContext context)
{
_context = context;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
// 检查是否标记了Transactional特性
if (request.GetType().GetCustomAttribute<TransactionalAttribute>() == null)
return await next();
await using var transaction = await _context.Database.BeginTransactionAsync(cancellationToken);
try
{
var response = await next();
await transaction.CommitAsync(cancellationToken);
return response;
}
catch
{
await transaction.RollbackAsync(cancellationToken);
throw;
}
}
}
3. 使用 MediatR 与 ASP.NET Core 集成
在控制器中使用 MediatR:
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
private readonly IMediator _mediator;
public UsersController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] CreateUserCommand command)
{
var userId = await _mediator.Send(command);
return CreatedAtAction(nameof(GetUser), new { id = userId }, null);
}
[HttpGet("{id}")]
public async Task<ActionResult<UserDto>> GetUser(int id)
{
var query = new GetUserByIdQuery { UserId = id };
var user = await _mediator.Send(query);
return Ok(user);
}
}
🌈 结语:MediatR 的修仙之道
1.通过今天的修炼,我们已经掌握了 MediatR 的五大境界:
- ✅ 基础搭建 - 初识 MediatR
- ✅ 命令与查询 - CQRS 模式实践
- ✅ 通知与事件 - 发布/订阅模式
- ✅ 管道行为 - 中间件式处理
- ✅ 高级技巧 - 验证、事务等
2.MediatR 就像一把瑞士军刀,在.NET 应用程序中提供了灵活的消息传递机制。它能够:
- ✅ 解耦组件之间的直接依赖
- ✅ 简化控制器逻辑
- ✅ 实现清晰的架构分层
- ✅ 方便地添加横切关注点
记住,修仙之路漫长,MediatR 只是其中一本秘籍。希望这篇日记能助你在.NET 的修仙之路上更进一步!
💡 小测验:
-
1.MediatR 主要实现了哪种设计模式?
-
2.命令和查询在 MediatR 中有什么区别?
-
3.如何为所有请求添加统一的日志记录?
欢迎在评论区分享你的答案和修炼心得!我们下期再见~
微信公众号【.NET修仙日记】
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)