使用领域事件

1.引言

最近刚学习了下DDD中领域事件的理论知识,总的来说领域事件主要有两个作用,一是解耦,二是使用领域事件进行事务的拆分,通过引入事件存储,来实现数据的最终一致性。若想了解DDD中领域事件的概念,可参考DDD理论学习系列(9)-- 领域事件。

Abp中使用事件总线来实现领域事件,而关于事件总线的实现,大家可参考我这篇博文——事件总线知多少,本文将不再赘述。

2.用例分析

当用户被成功分配任务后,发送邮件和消息通知给用户。

这个用例比较简单,没有太多的复杂逻辑,按照我们传统的思路,直接在任务编辑方法中添加邮件和消息发送的方法即可,代码如下:

public void UpdateTask(UpdateTaskInput input){   
 //We can use Logger, it's defined in ApplicationService base class.Logger.Info("Updating a task for input: " + input);    
 //获取是否有权限bool canAssignTaskToOther = PermissionChecker.IsGranted(PermissionNames.Pages_Tasks_AssignPerson);  
   //如果任务已经分配且未分配给自己,且不具有分配任务权限,则抛出异常if (input.AssignedPersonId.HasValue && input.AssignedPersonId.Value != AbpSession.GetUserId() &&!canAssignTaskToOther){        throw new AbpAuthorizationException("没有分配任务给他人的权限!");}    var updateTask = Mapper.Map<Task>(input);    var user = _userRepository.Get(input.AssignedPersonId.Value);    //先执行分配任务_taskManager.AssignTaskToPerson(updateTask, user);    //再更新其他字段_taskRepository.Update(updateTask);    //发送通知var message = "You hava been assigned one task into your todo list.";_smtpEmailSender.Send("ysjshengjie@qq.com", updateTask.AssignedPerson.EmailAddress, "New Todo item", message);_notificationPublisher.Publish("NewTask", new MessageNotificationData(message), null,NotificationSeverity.Info, new[] { updateTask.AssignedPerson.ToUserIdentifier() }); }

运行,直接挂掉。原因是很清楚,是由于邮箱配置有误导致。但是我们思考一下。我们进行任务分配时最关注的是任务被成功分配,而至于通知是否成功发送相对来说是次要的。但是现在却由于通知发送失败导致任务无非被成功分配,这是不合理的。

那我们要如何做呢?当然是拆分业务逻辑。而这时领域事件就可以粉墨登场了。

3.使用领域事件

就这个用例而言,“用户被成功分配任务”就是一个领域事件。下面我们就来实际应用一下。

3.1. 定义事件源

一个领域事件是通过事件源来识别的,我们直接定义一个TaskAssignedEventData继承自EventData即可:

public class TaskAssignedEventData : EventData{  

   public User User { get; set; }  
   public Task Task { get; set; }  
  
    public TaskAssignedEventData(Task task, User user)    {  
          this.Task = task;    
          this.User = user;} }

3.2. 实现事件处理

定义TaskAssignedToUser事件处理,实现IEventHandler<TaskAssignedEventData>泛型接口即可:

public class TaskAssignedToUser : IEventHandler<TaskAssignedEventData>, ITransientDependency
{   
   private readonly ISmtpEmailSender _smtpEmailSender;  
   private readonly INotificationPublisher _notificationPublisher;

      public TaskAssignedToUser(ISmtpEmailSender smtpEmailSender, INotificationPublisher notificationPublisher)    {_smtpEmailSender = smtpEmailSender;_notificationPublisher = notificationPublisher;}    public void HandleEvent(TaskAssignedEventData eventData)    {var message = "You hava been assigned one task into your todo list.";        //TODO:需要重新配置QQ邮箱密码_smtpEmailSender.Send("ysjshengjie@qq.com", eventData.Task.AssignedPerson.EmailAddress, "New Todo item", message);_notificationPublisher.Publish("NewTask", new MessageNotificationData(message), null,NotificationSeverity.Info, new[] { eventData.User.ToUserIdentifier() });} }

3.3. 事件触发

我们可以直接在上一节定义的TaskManager领域服务中触发领域事件。因为这样更符合当前领域事件通用语言的表述。

//TaskManager.cspublic void AssignTaskToPerson(Task task, User user){   
 //已经分配,就不再分配if (task.AssignedPersonId.HasValue && task.AssignedPersonId.Value == user.Id){      
   return;}  
  if (task.State != TaskState.Open){      
   throw new ApplicationException("处于非活动状态的任务不能分配!");}task.AssignedPersonId = user.Id;    //使用领域事件触发发送通知操作_eventBus.Trigger(new TaskAssignedEventData(task, user)); }

再运行,我们发现虽然没有接收到消息通知(发送失败),但任务却可以成功分配。

4. 一些问题

  1. 领域事件在哪注册(订阅)?
    应用程序启动时Abp根据约定俗成的命名规则将事件源和事件处理注册到了依赖容器中和事件总线维护的容器中。我们也可以自行在应用服务或领域服务中手动注册。

  2. 领域事件在哪触发(发布)?
    事件的触发同样也没有限定,根据需要,可以在应用服务、领域服务、聚合、实体中发布。

  3. 领域事件的命名?
    领域事件的名字要反映出过去发生的事情的概念。

4.最后

由于demo比较简单,找不到合适的用例,以上使用的用例比较简单。在复杂的用例中,当需要更新多个聚合时,领域事件的作用就体现出来了,借助领域事件我们可以很好的进行事务拆分,达到最终一致性的目的。

而至于领域事件衍生出来的事件存储和事件溯源,下次再和大家分享。

相关文章

  • DDD理论学习系列(1)-- 通用语言

  • DDD领域驱动之干货 (一)

  • DDD理论学习系列(2)-- 领域

  • DDD理论学习系列(3)-- 限界上下文

  • DDD理论学习系列(4)-- 领域模型

  • 事件总线知多少(2)

  • DDD理论学习系列(5)-- 统一建模语言

  • DDD理论学习系列(6)-- 实体

  • DDD理论学习系列(7)-- 值对象

  • DDD理论学习系列(8)-- 应用服务&领域服务

  • DDD理论学习系列(9)-- 领域事件

  • 从事件和DDD入手来构建微服务

  • DDD领域驱动之干货 (一)

  • WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例

  • 【DDD/CQRS/微服务架构案例】在Ubuntu 14.04.4 LTS中运行WeText项目的服务端

原文地址:http://www.cnblogs.com/sheng-jie/p/7136279.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ssl2331OJ1373-鱼塘钓鱼 之1【纯贪心】

前言 dp做法 堆优化贪心做法 题目&#xff1a;OJ1373 正题 有N个鱼塘&#xff0c;给出每分钟可以钓到的鱼数和每钓一次下一次钓减少的鱼数和到下一个鱼塘需要几分钟&#xff08;不能回头&#xff09;。求限定时间内最多能够钓到的鱼数 解题思路 由于数据较小&#xff0c;我…

手把手教会你(单/多)文件上传(并修改文件默认的最大最小值)

/*** MultipartFile 自动封装上传过来的文件* param email* param username* param headerImg* param photos* return*/PostMapping("/upload")public String upload(RequestParam("email") String email,RequestParam("username") String usern…

深入浅出讲解语言模型

转载自 深入浅出讲解语言模型 深入浅出讲解语言模型 1、什么是语言模型呢&#xff1f; 简单地说&#xff0c;语言模型就是用来计算一个句子的概率的模型&#xff0c;也就是判断一句话是否是人话的概率&#xff1f; 那么如何计算一个句子的概率呢&#xff1f;给定句子&…

set注意点map遍历

/** 使用各种set存储多个学生信息问题1&#xff1a;为什么课程名称&#xff08;String&#xff09;放入到HashSet、LinkedHashSet都可以保证唯一性&#xff0c;但是学生&#xff08;Student&#xff09;放入到HashSet、LinkedHashSet&#xff0c;却无法实现唯一性。问题2&…

《认知红利》读书笔记

认知红利 谢春霖 24个笔记 ◆ 上篇 概念重塑 所以&#xff0c;金钱并不是你的财富&#xff0c;而是你“已经交换出去的那部分财富”的数字存在形式而已。 总之&#xff0c;真不真不重要&#xff0c;对不对不重要&#xff0c;你看不看才重要&#xff01; 一片树叶从树上落下&am…

基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

一、前言 至今为止编程开发已经11个年头&#xff0c;从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展&#xff0c;从无畏无知的懵懂少年&#xff0c;到现在的中年大叔&#xff0c;从中的酸甜苦辣也只有本人自知。随着岁月的成长&#xff0c;技术也从原来的三层设计到…

ssl2331OJ1373-鱼塘钓鱼 之2【贪心堆优化】

前言 上篇&#xff1a;纯贪心做法 下篇&#xff1a;dp做法 题目&#xff1a;OJ1373 正题 有N个鱼塘&#xff0c;给出每分钟可以钓到的鱼数和每钓一次下一次钓减少的鱼数和到下一个鱼塘需要几分钟&#xff08;不能回头&#xff09;。求限定时间内最多能够钓到的鱼数 解题思路…

NLP Coursera By Michael Collins - Week1

转载自 NLP Coursera By Michael Collins - Week1 NLP Coursera By Michael Collins - Week1 构建模型框架 - Markov Process 毕竟是机器学习嘛&#xff0c;所以第一步&#xff0c;先要把实际问题转化成数学模型。 在NLP中&#xff0c;一般使用的都是概率模型&#xff0c;…

JDBC登录功能实现

模拟淘宝登录 package com.bjsxt.jdbc2;import com.bjsxt.entity.User; import entity.Emp;import java.nio.file.attribute.UserDefinedFileAttributeView; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Scanner;/*** 模拟淘宝登…

19级:班级日常分享,一天一瞬间

点击上方蓝色关注我们&#xff01;19级的同学们目前正在做KTV点歌系统项目&#xff0c;截止今日为止&#xff0c;项目已经进展了1天多了&#xff0c;进度还在可控范围内&#xff0c;大部分组的后台都已完成&#xff0c;刘娜小组稍微比较慢了点儿。李磊小组的进度最快&#xff0…

Attentive Sequence to Sequence Networks

转载自 Attentive Sequence to Sequence Networks Attentive Sequence to Sequence Networks 1、Encoder-Decoder 框架 首先我们模型的整体框图如下&#xff1a; Encoder-Decoder 框架可以这么直观地去理解&#xff1a;可以把它看作适合处理由一个句子&#xff08;或篇章&a…

ssl2331OJ1373-鱼塘钓鱼 之3【dp】

前言 上篇&#xff1a; 纯贪心做法 堆优化贪心 题目&#xff1a;OJ1373 正题 有N个鱼塘&#xff0c;给出每分钟可以钓到的鱼数和每钓一次下一次钓减少的鱼数和到下一个鱼塘需要几分钟&#xff08;不能回头&#xff09;。求限定时间内最多能够钓到的鱼数 解题思路 用f[i][…

多线程三种创建方式

方法一&#xff1a;继承Thread Thread package com.bjsxt.create;/*** author dell* data 2021/3/2* 创建一个线程对象&#xff0c;并启动线程** 注意&#xff1a;启动main方法&#xff0c;自动创建main线程* * thread.join() 阻塞乌龟线程&#xff0c;乌龟执行完…

20级四班班级管理规章制度

点击上方蓝色关注我们&#xff01;

完全图解RNN、RNN变体、Seq2Seq、Attention机制

转载自 完全图解RNN、RNN变体、Seq2Seq、Attention机制 完全图解RNN、RNN变体、Seq2Seq、Attention 机制 本文首发于知乎专栏“ai insight”&#xff01; 本文主要是利用图片的形式&#xff0c;详细地介绍了经典的RNN、RNN几个重要变体&#xff0c;以及Seq2Seq模型、Attent…

OJ1306-最长公共子上升序列【dp】

前言 这是一道比较久之前的题了&#xff0c;之前没做完。不过这次不是因为我改了&#xff0c;而是数据改了&#xff08;可能之前有问题&#xff09;&#xff0c;然后偶然今天翻的时候就发现自己对了QAQ。 题目 OJ1306 就是给出两个序列&#xff0c;求出这两个序列中公共的最…

多线程三种同步方式(模拟银行取款)

方法一&#xff1a;同步代码块 Accoun package com.bjsxt.synch1;/*** 银行账户类*/ public class Account {private int balance 600;//余额/*** 取款* param money*/public void withDraw(int money){this.balance this.balance -money;}/*** 查看余额* return*/public i…

今天就唠叨唠叨吧……

点击上方蓝色关注我们&#xff01;看书这个爱好是从去年年底开始的。看关于教育教学管理类型的书籍是从今年前半年开始的&#xff0c;有好些书都是王晓春老师写的&#xff0c;例如《做一个专业的班主任》、《问题学生诊疗手册》《今天怎样做教师》&#xff0c;每本书都有不一样…