代码解耦之道:MediatR在.NET中的实战应用

开发 开发工具
MediatR是一个强大的工具,可以帮助你构建松耦合、可维护的C#应用程序。通过分离请求和处理程序,它促进了关注点分离,并使得添加新功能和修改现有功能变得更加容易。

1. 引言

MediatR是一个轻量级的中介者模式实现库,用于在.NET应用程序中处理进程内消息传递。它有助于降低代码耦合度,提高可维护性和可测试性。本文将深入探讨MediatR的使用方法,并提供多个实际示例。

2. MediatR的核心概念

在深入示例之前,让我们先了解MediatR的几个核心概念:

  1. 请求(Request): 表示要执行的操作。
  2. 处理程序(Handler): 负责处理特定类型的请求。
  3. 中介者(Mediator): 协调请求和处理程序之间的通信。

3. 安装MediatR

首先,通过NuGet包管理器安装MediatR:

dotnet add package MediatR

4. 基本用法示例

4.1 创建请求和处理程序

让我们从一个简单的示例开始,创建一个获取用户信息的请求:

public class GetUserQuery : IRequest<UserDto>
{
    public int UserId { get; set; }
}


public class GetUserQueryHandler : IRequestHandler<GetUserQuery, UserDto>
{
    public async Task<UserDto> Handle(GetUserQuery request, CancellationToken cancellationToken)
    {
        // 模拟从数据库获取用户
        await Task.Delay(100, cancellationToken); // 模拟异步操作
        return new UserDto { Id = request.UserId, Name = $"User {request.UserId}" };
    }
}


public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

4.2 配置依赖注入

在Program.cs中配置MediatR:

builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
4.3 使用MediatR发送请求

在控制器或服务中使用MediatR:

public class UserController : ControllerBase
{
    private readonly IMediator _mediator;


    public UserController(IMediator mediator)
    {
        _mediator = mediator;
    }


    [HttpGet("{id}")]
    public async Task<ActionResult<UserDto>> GetUser(int id)
    {
        var query = new GetUserQuery { UserId = id };
        var result = await _mediator.Send(query);
        return Ok(result);
    }
}

5. 高级用法示例

5.1 使用通知(Notification)

通知允许多个处理程序响应同一个事件:

public class UserCreatedNotification : INotification
{
    public int UserId { get; set; }
    public string UserName { get; set; }
}


public class EmailNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    public Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Sending email for new user: {notification.UserName}");
        return Task.CompletedTask;
    }
}


public class LogNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    public Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Logging new user creation: {notification.UserId}");
        return Task.CompletedTask;
    }
}

使用通知:

await _mediator.Publish(new UserCreatedNotification { UserId = 1, UserName = "John Doe" });

5.2 使用管道行为(Pipeline Behavior)

管道行为允许你在处理请求之前和之后执行代码:

public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, 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($"开始处理请求 {typeof(TRequest).Name}");
        var response = await next();
        _logger.LogInformation($"完成处理请求 {typeof(TResponse).Name}");
        return response;
    }


}

注册管道行为:

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
触发:
var query = new GetUserQuery { UserId = 1 };
var result = await _mediator.Send(query);
return Ok();

6. 实现请求重试机制

创建一个行为来自动重试失败的请求:

public class RetryBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly ILogger<RetryBehavior<TRequest, TResponse>> _logger;
    private const int MaxRetries = 3;


    public RetryBehavior(ILogger<RetryBehavior<TRequest, TResponse>> logger)
{
        _logger = logger;
    }


    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        for (int i = 0; i <= MaxRetries; i++)
        {
            try
            {
                if (i > 0)
                {
                    _logger.LogWarning($"Retrying {typeof(TRequest).Name} (attempt {i})");
                }
                return await next();
            }
            catch (Exception ex) when (i < MaxRetries)
            {
                _logger.LogError(ex, $"Error handling {typeof(TRequest).Name}. Retry attempt {i + 1} of {MaxRetries}");
                await Task.Delay(1000 * i, cancellationToken);
            }
        }


        throw new Exception($"Failed to process {typeof(TRequest).Name} after {MaxRetries} retries.");
    }
}
// 在Program.cs中注册
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RetryBehavior<,>));

7. 最佳实践

  1. 保持请求和处理程序的简单性和单一职责。
  2. 使用通知处理跨切面关注点,如日志记录和事件发布。
  3. 利用管道行为实现横切关注点,如验证、日志记录和性能监控。
  4. 在大型项目中,考虑按功能或模块组织请求和处理程序。
  5. 使用依赖注入容器管理MediatR和其他依赖项。

8. 结论

MediatR是一个强大的工具,可以帮助你构建松耦合、可维护的C#应用程序。通过分离请求和处理程序,它促进了关注点分离,并使得添加新功能和修改现有功能变得更加容易。结合CQRS模式,MediatR可以成为构建可扩展和高性能应用程序的有力工具。

责任编辑:武晓燕 来源: 技术老小子
相关推荐

2024-12-05 09:13:55

Go项目模块

2020-11-20 15:22:32

架构运维技术

2009-02-27 16:22:34

AjaxProAjax.NET

2012-07-10 01:47:14

代码架构设计

2022-09-02 08:23:12

软件开发解耦架构

2024-09-30 09:48:41

RabbitMQ消息中间件

2016-11-30 15:30:42

架构工具和方案

2013-09-16 10:19:08

htmlcssJavaScript

2023-12-29 09:01:10

SwiftUI空状态Product​

2019-10-25 19:05:57

物联网人工智能技术

2021-03-10 05:50:06

IOCReact解耦组件

2024-03-08 16:27:22

领域事件DDD项目跨层解耦

2017-11-15 09:32:27

解耦战术架构

2022-08-08 20:48:09

MQ消息中间件系统解耦

2024-06-11 00:00:05

RabbitMQAMQP协议

2021-04-13 16:18:30

人工智能强化学习人脸识别

2019-06-20 10:23:23

架构代码前端

2022-04-15 11:46:09

轻量系统解耦鸿蒙操作系统

2018-04-18 08:47:17

Alluxio构建存储

2021-06-01 09:38:19

消息队列核心系统下游系统
点赞
收藏

51CTO技术栈公众号