[译]ASP.NET Core中使用MediatR实现命令和中介者模式

做者:依乐祝
原文地址:http://www.javashuo.com/article/p-bwogrvhz-me.htmlhtml

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

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

命令模式及其简单实例

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

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

一个简单的例子是多种类型的消息。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库支持两种类型的操做。asp.net

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

咱们已经介绍了命令模式,所以是时候定义一些命令并使用MediatR发出命令了。函数

在ASP.NET Core中安装

咱们须要从NuGet安装MediatR和MediatR.Extensions.Microsoft.DependencyInjection包。this

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

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

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

使用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/

相关文章
相关标签/搜索