在.NET 的修仙世界中,MediatR 就像是一本神奇的"传音入密"秘籍,它能让你的代码各司其职,却又心意相通。今天,就让我们一起来修炼这本秘籍,掌握.NET 中的中介者模式精髓! MediatR 是一个简单的中介者模式实现,它通过解耦消息发送者和接收者来简化应用程序中的进程内通信。简单来说,它就像是一个邮局,负责把你的"信件"(消息)准确无误地投递给正确的"收件人"(处理器)。
// 安装MediatR
dotnet add package MediatR
首先,我们需要在 Startup.cs 或 Program.cs 中注册 MediatR 服务:
// .NET 6+ 的Program.cs
builder.Services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
让我们从一个简单的"Hello World"开始:
// 定义消息
public class HelloWorldQuery:IRequest<string>
{
publicstring 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 模式。
// 创建用户命令
public class CreateUserCommand:IRequest<int>
{
public string Username {get;set;}
public string Email {get;set;}
}
public class CreateUserHandler
:IRequestHandler<CreateUserCommand,int>
{
privatereadonlyApplicationDbContext _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;
}
}
// 获取用户详情查询
public class GetUserByIdQuery:IRequest<UserDto>
{
publicint UserId {get;set;}
}
public class GetUserByIdHandler
:IRequestHandler<GetUserByIdQuery, UserDto>
{
privatereadonlyApplicationDbContext _context;
public GetUserByIdHandler(ApplicationDbContext context)
{
_context = context;
}
public asyncTask<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 接口实现。
publicclassUserCreatedNotification:INotification
{
public int UserId {get;set;}
public string Username {get;set;}
public DateTime CreatedAt {get;set;}
}
// 发送欢迎邮件处理器
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;
}
}
await mediator.Publish(new UserCreatedNotification
{
UserId = newUserId,
Username = command.Username,
CreatedAt = DateTime.UtcNow
});
MediatR 的管道行为(Pipeline Behaviors)类似于 ASP.NET Core 的中间件,可以在处理请求前后执行逻辑
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;
}
}
}
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();
}
}
builder.Services.AddTransient(typeof(IPipelineBehavior<,>),typeof(LoggingBehavior<,>));
builder.Services.AddTransient(typeof(IPipelineBehavior<,>),typeof(ValidationBehavior<,>));
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>();
// 自定义特性
[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;
}
}
}
在控制器中使用 MediatR:
[ApiController]
[Route("api/users")]
public class UsersController:ControllerBase
{
privatereadonlyIMediator _mediator;
publicUsersController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
publicasyncTask<IActionResult>CreateUser([FromBody]CreateUserCommand command)
{
var userId =await _mediator.Send(command);
returnCreatedAtAction(nameof(GetUser),new{ id = userId },null);
}
[HttpGet("{id}")]
publicasyncTask<ActionResult<UserDto>>GetUser(int id)
{
var query =newGetUserByIdQuery{ UserId = id };
var user =await _mediator.Send(query);
returnOk(user);
}
}
记住,修仙之路漫长,MediatR 只是其中一本秘籍。希望这篇日记能助你在.NET 的修仙之路上更进一步!
欢迎在评论区分享你的答案和修炼心得!我们下期再见~
(点击关注,修炼不迷路👇)
▌转载请注明出处,渡人渡己
🌟 感谢道友结缘! 若本文助您突破修为瓶颈,不妨[打赏灵丹]或[转发功德],让更多.NET道友共参CLR天道玄机。修真之路漫漫,我们以代码为符,共绘仙途!
(随缘赞赏即可)