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

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

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

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

命令模式及其简单实例

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

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

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

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();
        }
    }  

输出

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

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

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

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

MediatR库如何帮助我们

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

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

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

在ASP.NET Core中安装

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

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

现在,我们可以使用.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/

原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html

时间: 2024-10-07 11:09:35

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

NET Core中使用MediatR实现命令和中介者模式

NET Core中使用MediatR实现命令和中介者模式 https://www.cnblogs.com/yilezhu/p/9866068.html 在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何在ASP.NET Core中使用它来解决我们的问题并使代码简洁.因此,我们将通过下面的主题来进行相关的讲解. 什么是命令模式? 命令模式的简单实例以及中介者模式的简单描述 MVC中的瘦控制器是什么?我们是如何实现使控制器变瘦的? 我们如何在我们的.NET Core应

【翻译】asp.net core中使用MediatR

这篇文章来自:https://ardalis.com/using-mediatr-in-aspnet-core-apps 本文作为翻译,有一些单词翻译成中文可能会有一些误解(对于读者)或者错误(对于作者)的地方,所以在文章中你可以看到一些单词没有进行翻译.如果有不对的地方,请指出,谢谢. 在Asp.net core中使用MediatR 我已经开始考虑使用MediatR作为我的领域事件实现.为了达到这个目的,我用asp.net core创建了一个示例程序,总的来说是非常容易的,如果你之前没有使用过

Asp.net core中的websocket

Websocket是html5后的产物,对于asp.net core中也得到了支持,首先在NuGet中添加Microsoft.AspNetCore.WebSockets的引用(现在是1.0.1版本,2017年3月7日发布的). 首先在Configure中添加中间件 //添加websocket中间件 app.UseWebSockets(); 接下来就要定义自己处理websocket的中间件了,代码如下: using Microsoft.AspNetCore.Http; using System;

ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【解读ServiceCallSite 】

通过上一篇的介绍我们应该对实现在ServiceProvider的总体设计有了一个大致的了解,但是我们刻意回避一个重要的话题,即服务实例最终究竟是采用何种方式提供出来的.ServiceProvider最终采用何种方式提供我们所需的服务实例取决于最终选择了怎样的ServiceCallSite,而服务注册是采用的ServiceDescriptor有决定了ServiceCallSite类型的选择.我们将众多不同类型的ServiceCallSite大体分成两组,一组用来创建最终的服务实例,另一类则与生命周

如何在ASP.NET Core中应用Entity Framework

注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity Framework 首先为大家提醒一点,.NET Core和经典.NET Framework的Library是不通用的,包括Entity Framework! 哪怎么办? 别急,微软为.NET Core发布了.NET Core版本的Entity Framework,具体配置方法与经典.NET Framew

如何在ASP.NET Core中实现一个基础的身份认证

注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ASP.NET终于可以跨平台了,但是不是我们常用的ASP.NET, 而是叫一个ASP.NET Core的新平台,他可以跨Windows, Linux, OS X等平台来部署你的web应用程序,你可以理解为,这个框架就是ASP.NET的下一个版本,相对于传统ASP.NET程序,它还是有一些不同的地方的,比

ASP.NET Core中使用xUnit进行单元测试

单元测试的功能自从MVC的第一个版本诞生的时候,就是作为一个重要的卖点来介绍的,通常在拿MVC与webform比较的时候,单元测试就是必杀底牌,把webform碾压得一无是处. 单元测试的重要性不用多说了,有单元测试的做兜底的项目,好比给开发人员买了份保险,当然这个保险的质量取决于单元测试的质量,那些一路Mock的单元测试,看起来很美,但是什么都cover不到.目前工作中的一个老项目,有2万多个单元测试用例,其中不少是用心之作,真正落实到了业务逻辑,开发人员可以放心的去修改代码,当然一切都必须按

ASP.NET Core中的依赖注入(2):依赖注入(DI)

参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/project-layout.html http://www.yuanjiaocheng.net/ASPNET-CORE/projectjson.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-configuration.html http://www.yuanjiaocheng.net/ASPNET-CORE/core-middleware.htm

NLog在asp.net core中的应用

Asp.net core中,自带的Log是在当selfhost运行时,在控制台中输出,不便于查阅,如果用一个log架框,把日志持久化,便于查询. NLog是一个免费的日志记录框架,专门为.net平台下的框架提供日志功能,本文主要说明asp.net core下怎么使用NLog. 首先用Nuget安装NLog.Extensions.Logging和NLog.Web.AspNetCore两个类库. 修改project.json,在publishOptions中添加"nlog.config节点"