码迷,mamicode.com
首页 > Web开发 > 详细

.Net5 中使用Mediatr 中介者模式下的CQRS

时间:2021-01-11 11:12:20      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:line   token   strong   一个   方式   wait   ebe   bool   简单   

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

注册失败流程

技术图片

 

.Net5 中使用Mediatr 中介者模式下的CQRS

标签:line   token   strong   一个   方式   wait   ebe   bool   简单   

原文地址:https://www.cnblogs.com/acmeblogs/p/14252076.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!