zoukankan      html  css  js  c++  java
  • .Net5 中使用Mediatr 中介者模式下的CQRS

    CQRS(Command Query Responsibility Segregation)命令查询职责分离模式

    目标:在控制台中使用Mediatr实现一个简单用户注册场景

    • 用户发起用户注册
    • 注册成功,发送电子邮件给用户(还可以做其他事情)
    • 注册失败,日志记录

    控制台程序结构目录

     主程序Program.cs 中的代码

    class Program
        {
            static async Task Main(string[] args)
            {
                IServiceCollection services = new ServiceCollection();
                services.AddLogging(logBuilder =>
                {
                    logBuilder.AddConsole();
                });
                services.AddMediatR(Assembly.GetExecutingAssembly());
                services.AddScoped(typeof(IPipelineBehavior<,>), typeof(MyLoggerBehavior<,>));
                var sp = services.BuildServiceProvider();
                var mediator = sp.GetRequiredService<IMediator>();
    
                Console.WriteLine("Hello World!");
                while (true)
                {
                    var ss = Console.ReadLine();
                    Console.WriteLine("------------------注册流程开始-------------------------------------");
                    mediator.Send(new RegisterCommand("Admin", "123", "123@163.com"));
                }
            }
        }
    

      

    使用Mediatr 需要引用程序集

     

    PM> Install-Package MediatR
    

     

      Mediatr 的核心接口

     

    • IMeditator
    • IRequest 与IRequestHandler<in TRequest, TResponse>接口,这两个接口是成对存在,一对一关系
    • INotification与INotificationHandler<in TNotification>接口,是一对多关系

    第一步:使用IRequest 创建一个用户注册请求

    public class RegisterCommand:IRequest<bool>
        {
            public string UserName { get; private set; }
            public string Password { get; private set; }
            public string Email { get; private set; }
    
            public RegisterCommand(string userName, string password, string email)
            {
                UserName = userName;
                Password = password;
                Email = email;
            }
        }
    

    第二步:使用IRequestHandler<in TRequest, TResponse>接口 创建一个 “注册请求处理处理程序”

      public class RegisterCommandHandler : IRequestHandler<RegisterCommand,bool>
        {
            private readonly ILogger<RegisterCommandHandler> _logger;
            private readonly IMediator _mediator;
    
            public RegisterCommandHandler(ILogger<RegisterCommandHandler> logger, IMediator mediator)
            {
                _logger = logger;
                _mediator = mediator;
            }
    
            public async Task<bool> Handle(RegisterCommand request, CancellationToken cancellationToken)
            {
    
                _logger.LogInformation($"注册命令处理开始时间:{DateTime.Now}==模拟延时1秒注册");
                await Task.Delay(1000);
                if (DateTime.Now.Second % 2 == 0)
                {
                    _logger.LogInformation($"当前时间:{DateTime.Now}=====注册成功==用户名:{request.UserName}");
                    _mediator.Publish(new RegisterSucEvent(request.Email));
                }
                else {
                    _logger.LogInformation($"当前时间:{DateTime.Now}=====注册失败==用户名:{request.UserName}");
                    _mediator.Publish(new RegisterFailEvent(request.UserName));
                }
               
                _logger.LogInformation($"注册命令处理结束时间:{DateTime.Now}");
                return true;
            }
        }
    

    第三步 使用INotification 接口 两个 通知事件,一个是注册成功事件,另一个是注册失败事件,以及对应的事件处理程序,注册成功事件我写了两个处理程序

    注册成功事件

     public class RegisterSucEvent : INotification
        {
            public string Email { get; private set; }
    
            public RegisterSucEvent(string email)
            {
                Email = email;
            }
        }
    

      

    注册成功事件处理程序1

       public class RegisterSucEventHandler : INotificationHandler<RegisterSucEvent>
        {
            private readonly ILogger<RegisterSucEventHandler> _logger;
    
            public RegisterSucEventHandler(ILogger<RegisterSucEventHandler> logger)
            {
                _logger = logger;
            }
    
            public async Task Handle(RegisterSucEvent notification, CancellationToken cancellationToken)
            {
                _logger.LogInformation($"RegisterSucEventHandler处理开始时间:{DateTime.Now}==模拟延时5秒发送");
                await Task.Delay(5000);
                _logger.LogInformation($"时间:{DateTime.Now}=====发送电子邮件给{notification.Email}");
                _logger.LogInformation($"RegisterSucEventHandler处理结束时间:{DateTime.Now}");
            }
        }
    

      

    注册成功事件处理程序2

      public class RegisterSucEventHandlerV2 : INotificationHandler<RegisterSucEvent>
        {
            private readonly ILogger<RegisterSucEventHandlerV2> _logger;
    
            public RegisterSucEventHandlerV2(ILogger<RegisterSucEventHandlerV2> logger)
            {
                _logger = logger;
            }
    
            public async Task Handle(RegisterSucEvent notification, CancellationToken cancellationToken)
            {
                _logger.LogInformation($"RegisterSucEventHandlerV2处理开始时间:{DateTime.Now}==模拟延时5秒发送");
                await Task.Delay(5000);
                _logger.LogInformation($"吼了两嗓子,用时5秒!");
                _logger.LogInformation($"RegisterSucEventHandlerV2处理结束时间:{DateTime.Now}");
            }
        }
    

      

    注册失败事件

    public class RegisterFailEvent:INotification
        {
            public string UserName { get; private set; }
    
            public RegisterFailEvent(string userName)
            {
                UserName = userName;
            }
        }
    

      

    注册失败事件事件

    public class RegisterFailEventHandler : INotificationHandler<RegisterFailEvent>
        {
            private readonly ILogger<RegisterFailEventHandler> _logger;
    
            public RegisterFailEventHandler(ILogger<RegisterFailEventHandler> logger)
            {
                _logger = logger;
            }
    
            public async Task Handle(RegisterFailEvent notification, CancellationToken cancellationToken)
            {
                _logger.LogError($"RegisterFailEventHandler处理开始时间:{DateTime.Now}");
                _logger.LogError($"时间:{DateTime.Now}=====用户名:{notification.UserName}注册失败");
                _logger.LogError($"RegisterFailEventHandler处理结束时间:{DateTime.Now}");
            }
        }
    

      Mediatr 还有一个管道接口IPipelineBehavior<TRequest, TResponse>,类似于Aop 编程,可以在IRequest 命令执行前或者执行后加入一些代码逻辑

    本程序页实现了一个简单的日志记录行为

     public class MyLoggerBehavior<TRequest,TResponse>:IPipelineBehavior<TRequest, TResponse>
        {
            private readonly ILogger<MyLoggerBehavior<TRequest, TResponse>>  _logger;
    
            public MyLoggerBehavior(ILogger<MyLoggerBehavior<TRequest, TResponse>> logger)
            {
                _logger = logger;
            }
    
            public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
            {
                _logger.LogInformation($"命令执行前=={DateTime.Now}");
                var result= await next();
                _logger.LogInformation($"命令执行后=={DateTime.Now}");
                return result;
            }
        }
    

      

    OK 整理的代码已经撸完,先理一下执行过程:

    主程序启动进行用户注册==>注册成功(延时一秒钟)分别执行RegisterSucEventHandler与RegisterSucEventHandlerV2 处理程序,这个两个程序都要延时5秒钟执行

    看下程序执行结果,采用异步的方式

     其中RegisterSucEvent有两个处理程序,首先25秒时执行了RegisterSucEventHandler 在30秒执行了RegisterSucEventHandlerV2

    注册失败流程

  • 相关阅读:
    STL实现的底层数据结构简介
    C++ STL中Map的按Key排序和按Value排序
    algorithm库介绍之---- stable_sort()方法 与 sort()方法 .
    git取消更改 恢复版本命令
    unbuntu下清理磁盘空间
    x265编码命令
    SQLServer数据库获取重复记录中日期最新的记录
    牛逼哄哄的 Lambda 表达式,简洁优雅就是生产力!
    哎!又要过年了,程序员最怕问到什么?
    swagger 使用指南
  • 原文地址:https://www.cnblogs.com/acmeblogs/p/14252076.html
Copyright © 2011-2022 走看看