zoukankan      html  css  js  c++  java
  • [译]使用mediatR的notification来扩展的的应用

    原文

    你不希望在controller里面出现任何领域知识

    开发者经常有这样的疑问“这个代码应该放在哪呢?”应该使用仓储还是query类?....

    怎么去实现职责分离和单一职责呢?

    MediatR Notifications能帮助我们。

    例子

    假设你有一个简单的网站,有一个页面提供一个简单的联系我们的表单。

    当客户完成了这个表单,会发送一封邮件给网站管理者。

    public IHttpActionResult Post([FromBody]ContactUsForm contactUs)
    {
        var mailMessage = new MailMessage(contactUs.EmailAddress, "you@yoursite.com"); 
        mailMessage.Subject = "Contact from web site";
        mailMessage.Body = contactUs.Message;            
    
        var smtp = new SmtpClient();
        smtp.Send(mailMessage);
    
        return Ok();
    }
    

    现在你老板过来要求你将这个信息往数据库里面也放一份,以方便做一些报表统计。

    然后你修改controller,加入了下面的一下代码:

    public IHttpActionResult Post([FromBody]ContactUsForm contactUs)
    {
        var mailMessage = new MailMessage(contactUs.EmailAddress, "you@yoursite.com"); 
        mailMessage.Subject = "Contact from web site";
        mailMessage.Body = contactUs.Message;            
    
        var smtp = new SmtpClient();
        smtp.Send(mailMessage);
    
        var userMessage = new UserMessage {
            Received = System.DateTime.Now,
            UserEmailAddress = contactUs.EmailAddress,
            UserFullName = contactUs.FullName
        };
        db.UserMessages.Add(userMessage);
        db.SaveChanges();
    
        return Ok();
    }
    

    现在单一职责被破坏了,但是你决定先这么处理不管了。

    你老板是一个从来不容易满足的人,过了几天他又过来了,他希望将这个表单里面的客户信息存储到CRM系统中。

    现在你的controller变成这样了:

    public class ContactController : ApiController
    {
    using BlogSite.Models;
    using BlogSite.Models.Crm;
    using System.Net.Mail;
    using System.Web.Http;
    
    namespace BlogSite.Controllers.Api
    {
        public class ContactController : ApiController
        {
            private ApplicationDbContext db = new ApplicationDbContext();        
    
            public IHttpActionResult Post([FromBody]ContactUsForm contactUs)
            {
                var mailMessage = new MailMessage(contactUs.EmailAddress, "you@yoursite.com");
                mailMessage.Subject = "Contact from web site";
                mailMessage.Body = contactUs.Message;
    
                var smtp = new SmtpClient();
                smtp.Send(mailMessage);
    
                var userMessage = new UserMessage
                {
                    Received = System.DateTime.Now,
                    UserEmailAddress = contactUs.EmailAddress,
                    UserFullName = contactUs.FullName
                };
                db.UserMessages.Add(userMessage);
                db.SaveChanges();
    
                var crm = new CrmInterface();
                crm.Connect();
                crm.SaveContact(new CrmContact { EmailAddress = contactUs.EmailAddress, FullName = contactUs.FullName });
    
                return Ok();
            }
        }
      }
    }
    

    评估/回顾(Taking stock)

    这种需求还在不断的增加。每一个新需求都需要修改已有的controller。

    这存在一个潜在的风险。对存在的代码的每次修改都有可能破坏现有的功能。

    而且这些代码是同步执行的。如果你的CRM系统或者邮件服务器挂了或者变慢了,你的客户在提交表单的页面要等待许久。

    分离职责

    现在,很明显controller承担了太多的工作。有一种解决方案是将不同的职责放到他们自己的类中去。

    using BlogSite.Services.Crm;
    using BlogSite.Services.Data;
    using BlogSite.Services.Email;
    using System.Web.Http;
    
    namespace BlogSite.Controllers.Api
    {
        public class ContactController : ApiController
        {
            private IEmailService _emailService;
            private IUserMessageService _userMessageService;
            private ICrm _crm;
    
            public ContactController(IEmailService emailService, IUserMessageService userMessageService, ICrm crm)
            {
                _emailService = emailService;
                _userMessageService = userMessageService;
                _crm = crm;
            }
    
            public IHttpActionResult Post([FromBody]ContactUsForm contactUs)
            {
                _emailService.Send(contactUs.EmailAddress, "you@yoursite.net", "Contact from web site", contactUs.Message);
                _userMessageService.RecordUserMessageReceived(contactUs.EmailAddress, contactUs.FullName);
                _crm.SaveContact(new CrmContact { EmailAddress = contactUs.EmailAddress, FullName = contactUs.FullName });
                return Ok();
            }
        }
    }
    

    好些了,职责分离了,controller看起来整洁些了。

    然后你还是在同步的运行(在这个例子中异步执行更好),controller和应用服务产生了耦合。如果要加什么新特性,你仍然需要修改controller。

    使用MediatR Notifications

    MediatR能给我们什么帮助呢?

    比起在action里面写一些业务逻辑,MediatR可以让我们发布一个通知。

    通知可以是异步或者同步的。

    public class ContactController : ApiController
    {
        private IMediator _mediator;
    
        public ContactController(IMediator mediator)
        {
            _mediator = mediator;
        }
    
        public async Task<IHttpActionResult> Post([FromBody]ContactUsForm contactUs)
        {
            var messageReceivedFromUserNotification = new MessageReceivedFromUserNotification {
                EmailAddress = contactUs.EmailAddress,
                FullName = contactUs.FullName,
                Message = contactUs.Message,
                SubmittedAt = DateTime.Now
            };
            await _mediator.PublishAsync(messageReceivedFromUserNotification);
    
            return Ok();
        }
    }
    

    notification是一个通知,代表了一个通知的详细信息。

    public class MessageReceivedFromUserNotification : IAsyncNotification
    {
        public DateTime SubmittedAt { get; set; }
        public string FullName { get; set; }
        public string EmailAddress { get; set; }
        public string Message { get; set; }
    }
    

    接下来你需要为不同的action写不同的handler。

    public class SaveUserMessage : IAsyncNotificationHandler<MessageReceivedFromUserNotification>
    {
        private ApplicationDbContext db = new ApplicationDbContext();
    
        public async Task Handle(MessageReceivedFromUserNotification notification)
        {
            var userMessage = new UserMessage
            {
                Received = notification.SubmittedAt,
                UserEmailAddress = notification.EmailAddress,
                UserFullName = notification.FullName
            };
            db.UserMessages.Add(userMessage);
            await db.SaveChangesAsync();
        }
    }
    
    public class NotifySalesUserMessageReceived : IAsyncNotificationHandler<MessageReceivedFromUserNotification>
    {
        public async Task Handle(MessageReceivedFromUserNotification notification)
        {
            var mailMessage = new MailMessage(notification.EmailAddress, "you@yoursite.com");
            mailMessage.Subject = "Contact from web site";
            mailMessage.Body = notification.Message;
    
            var smtp = new SmtpClient();
            await smtp.SendMailAsync(mailMessage);
        }
    }
    
  • 相关阅读:
    python验证卡普耶卡(D.R.Kaprekar)6174猜想
    关于java环境变量配置出现javac命令无法运行的解决办法
    关于QQ农场牧场等曾经流行的游戏的一些见解
    个人博客九
    个人博客八
    个人博客七
    个人博客六
    第十一周学习进度
    个人博客五
    个人博客四
  • 原文地址:https://www.cnblogs.com/irocker/p/how-to-easily-extend-your-app-using-mediatr-notifications.html
Copyright © 2011-2022 走看看