[譯]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/

相關文章
相關標籤/搜索