zoukankan      html  css  js  c++  java
  • [译]ASP.NET Core中使用MediatR实现命令和中介者模式

    作者:依乐祝
    原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html

    在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何在ASP.NET Core中使用它来解决我们的问题并使代码简洁。因此,我们将通过下面的主题来进行相关的讲解。

    • 什么是命令模式?
    • 命令模式的简单实例以及中介者模式的简单描述
    • MVC中的瘦控制器是什么?我们是如何实现使控制器变瘦的?
    • 我们如何在我们的.NET Core应用程序中使用MediatR
    • 使用命令和事件的实例

    命令模式及其简单实例

    从根本上讲,命令模式是一种数据驱动的设计模式,属于行为模式的范畴。命令是我们可以执行的某种操作或行为,它可以是活动的一部分。一个活动可以有一个或多个命令和实现。

    我们可以这样来说,请求以命令的形式包裹在对象中,并传给调用对象。调用者(代理)对象查找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令 。

    一个简单的例子是多种类型的消息。Message类包含SendEmail()和SendSms()等属性和方法。使用两种类型的命令,并且需要一个接口,它应该由实现了EmailMessageCommand和SMSMessageCommand的类类继承。还使用代理类来调用特定类型的消息类来处理操作。

    Mediatr

    Main class

    class Program  
        {  
            static void Main(string[] args)  
            {  
                Message message = new Message();  
                message.CustomMessage = "Welcome by Email";  
                EmailMessageCommand emailMessageCommand = new EmailMessageCommand(message);  
      
                Message message2 = new Message();  
                message2.CustomMessage = "Welcome by SMS";  
                SmsMessageCommand smsMessageCommand = new SmsMessageCommand(message2);  
      
                Broker broker = new Broker();  
                broker.SendMessage(emailMessageCommand);  
                broker.SendMessage(smsMessageCommand);  
                Console.ReadKey();  
      
            }  
        }  
    

    消息类

    public class Message  
        {  
            public string CustomMessage { get; set; }  
      
            public void EmailMessage()  
            {  
                Console.WriteLine($"{CustomMessage} : Email Message sent");  
            }  
      
            public void SmsMessage()  
            {  
                Console.WriteLine($"{CustomMessage} : Sms Message sent");  
            }  
        }  
    

    接口和代理类

    public interface IMessageCommand  
    {  
        void DoAction();         
    }  
      
    public class Broker  
    {  
        public void SendMessage(IMessageCommand command)  
        {  
            command.DoAction();  
        }  
    }  
    

    命令

    public class EmailMessageCommand : IMessageCommand  
        {  
            private Message oMessage;  
      
            public EmailMessageCommand(Message oMessage)  
            {  
                this.oMessage = oMessage;  
            }  
      
            public void DoAction()  
            {  
                oMessage.EmailMessage();  
            }  
        }  
      
        public class SmsMessageCommand : IMessageCommand  
        {  
            private Message oMessage;  
      
            public SmsMessageCommand(Message oMessage)  
            {  
                this.oMessage = oMessage;  
            }  
            public void DoAction()  
            {  
                 
                oMessage.SmsMessage();  
            }  
        }  
    

    输出

    Command, Mediator Pattern In ASP.NET Core Using Mediatr

    什么是瘦控制器,我们为什么需要它?什么是MediatR?

    当我们开始使用MVC框架进行开发时,逻辑是用控制器的动作方法编写的;就像我们有一个简单的电子商务应用程序,其中用户应该会下订单。我们有一个控制器,OrderController,用来管理订单。当用户下订单时,我们应该在数据库中保存记录。
    在此之前,我们有一个简化的代码。然而,经过一段时间后,我们意识到还有一个确认电子邮件的业务需求。现在,第二步是发送确认电子邮件给客户。后来,我们意识到,在这个步骤之后,我们还需要执行另一个操作,即,记录信息等。最后,我们还需要将用户的信息保存到CRM中。关键是它会增长控制器的大小。现在,我们可以称之为“臃肿控制器”。
    基于命令的体系结构允许我们发送命令来执行某些操作,并且我们有单独的命令处理程序,使关注点分离和提高单一职责。为了实现这个架构,我们可以使用第三方库,比如MediatR(Mediator.),它为我们做了很多基础工作。中介模式定义了一个对象,该对象封装了一组对象是如何交互的。

    中介模式的优势及MediatR如何帮助我们实现中介模式

    • 中介模式定义了一个对象,该对象封装了一组对象是如何交互的(如维基百科定义的)。
    • 它通过保持对象彼此明确地相互引用来促进松散耦合。
    • 它通过允许通信被卸载到一个只处理这类的类来促进单一责任原则。

    MediatR库如何帮助我们

    MediatR允许我们通过让控制器Action向处理程序发送请求消息来将控制器与业务逻辑解耦。MediatR库支持两种类型的操作。

    • 命令(预期输出结果)
    • 事件(请求者不关心接下来发生了什么,不期待结果)

    我们已经介绍了命令模式,因此是时候定义一些命令并使用MediatR发出命令了。

    在ASP.NET Core中安装

    我们需要从NuGet安装MediatR和MediatR.Extensions.Microsoft.DependencyInjection包。

    使用Mediatr在ASP.NET核心中的命ä"¤ï¼Œä"‹ä½“模式

    使用Mediatr在ASP.NET核心中的命ä"¤ï¼Œä"‹ä½“模式

    当这两个软件包安装完毕后,我们需要添加services.AddMediatR(); 到startup.cs文件。看起来像这样。

    使用Mediatr在ASP.NET核心中的命ä"¤ï¼Œä"‹ä½“模式

    现在,我们可以使用.NET Core 项目中的MediatR了。

    实例

    第一个示例演示了使用MediatR使用请求/响应类型的操作。它期望对请求做出一些反应。
    第二个示例将向您展示一个事件,其中多个处理程序执行它们的工作,调用者并不关心接下来会发生什么,也不期望任何结果/响应。

    第一个例子

    在这种场景下,我们希望注册用户并期望对请求做出一些响应。如果响应返回true,我们可以像登录用户一样进行进一步的操作。
    首先,我们需要创建一个继承自IRequest的类。

    public class NewUser: IRequest<bool>  
      {  
          public string Username { get; set; }  
          public string Password { get; set; }          
      }  
    

    IRequest是指请求的响应是布尔响应。
    现在,需要一个处理程序来处理这种类型的请求。

    public class NewUserHandler : IRequestHandler<NewUser, bool>  
      {         
          public Task<bool> Handle(NewUser request, CancellationToken cancellationToken)  
          {  
              // save to database  
              return Task.FromResult(true);  
          }  
      }  
    

    现在我们有了命令和它的处理程序,我们可以调用MediatR在我们的控制器中做一些操作。
    这些是Home控制器的动作方法。

    public class HomeController : Controller  
        {  
            private readonly IMediator _mediator;  
      
            public HomeController(IMediator mediator)  
            {  
                _mediator = mediator;  
            }  
           [HttpGet]  
            public ActionResult Register()  
            {  
                return View();  
            }  
      
            [HttpPost]  
            public ActionResult Register(NewUser user)  
            {  
                bool result = _mediator.Send(user).Result;  
      
                if (result)  
                    return RedirectToAction("Login");  
                  
                return View();  
            }  
          }  
    

    第一个例子的结论

    注册操作方法使用了[HttpPost]属性进行修饰,并接受新的用户注册请求。然后,它请求MediatR 进行处理。它期望来自请求的结果/响应,如果结果是真的,则将用户重定向到登录页面。
    这里,我们有简洁的代码,大部分的工作是在控制器外部完成的。这实现了对不同操作的处理的关注点分离(SoC)和单一责任的分离。
    在第二个示例中,我们将演示使用多个处理程序对命令执行不同操作的场景。

    第二个实例

    在这种情况下,我们使NewUser 继承了INotification

    public class NewUser : INotification  
    {  
        public string Username { get; set; }  
        public string Password { get; set; }  
    }  
    

    现在,有三个处理程序逐个执行,以完成他们的工作。这些都是从INotificationHandler继承下来的。

    public class NewUserHandler : INotificationHandler<NewUser>  
        {  
            public Task Handle(NewUser notification, CancellationToken cancellationToken)  
            {  
                //Save to log  
                Debug.WriteLine(" ****  Save user in database  *****");  
                return Task.FromResult(true);  
            }  
        }  
    

    第二个处理程序在下面的代码中定义。

    public class EmailHandler : INotificationHandler<NewUser>  
        {  
            public Task Handle(NewUser notification, CancellationToken cancellationToken)  
            {  
                //Send email  
                Debug.WriteLine(" ****  Email sent to user  *****");  
                return Task.FromResult(true);  
            }  
        }  
    

    这是第三个处理程序的代码

    public class LogHandler : INotificationHandler<NewUser>  
        {  
            public Task Handle(NewUser notification, CancellationToken cancellationToken)  
            {  
                //Save to log  
                Debug.WriteLine(" ****  User save to log  *****");  
                return Task.FromResult(true);  
            }  
        }  
    

    然后,我们控制器中的代码像下面这样

    public class AccountsController : Controller  
        {  
            private readonly IMediator _mediator;  
            public AccountsController(IMediator mediator)  
            {  
                _mediator = mediator;  
            }  
            [HttpGet]  
            public ActionResult Login()  
            {  
                return View();  
            }  
            [HttpGet]  
            public ActionResult Register()  
            {  
                return View();  
            }  
      
            [HttpPost]  
            public ActionResult Register(NewUser user)  
            {  
                _mediator.Publish(user);  
                return RedirectToAction("Login");  
            }  
        }  
    

    第二个例子的结论

    此应用程序的输出如下:
    当用户注册后,三个处理程序逐个执行——分别是NewUserHandler、EmailHandler和LogHandler,并执行它们的操作。

    这里,我们使用了Publish 方法,而不是Send 函数。发布将调用订阅了NewUser 类的所有处理程序。这只是一个示例,我们可以根据命令进行思考,然后按照我们在命令模式中讨论的方式相应地执行一些操作。

    Mediatr是如何提供帮助的?

    它可以用来隐藏实现的细节,用来使控制器代码更加干净和可维护,可以重用多个处理程序,并且每个处理程序都有自己的责任,因此易于管理和维护。

    在我的下一篇文章中,我将尝试解释CQRS架构模式及其优点以及如何使用MediatR来实现CQRS。

    原文地址:https://www.c-sharpcorner.com/article/command-mediator-pattern-in-asp-net-core-using-mediatr2/

  • 相关阅读:
    Google资深工程师深度讲解Go语言测试与性能调优(八)
    linux命令 对日志文件的IP出现的次数进行统计 并显示次数最多的前六名
    Java之不允许变量重定义
    Java之数组
    ATL之STDTHUNK
    Java之访问控制
    Java之线程初步II
    Android之Activating Components
    ATL之如何聚合一个组件
    WTL中对话框数据交换
  • 原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html
Copyright © 2011-2022 走看看