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

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

作者:圣杰
链接:https://www.jianshu.com/p/cb468618d7b6
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

ABP入门系列(19)——使用领域事件相关推荐

  1. ABP入门系列(7)——分页实现

    ABP入门系列目录--学习Abp框架之实操演练 完成了任务清单的增删改查,咱们来讲一讲必不可少的的分页功能. 首先很庆幸ABP已经帮我们封装了分页实现,实在是贴心啊. 来来来,这一节咱们就来捋一捋如何 ...

  2. ABP入门系列(14)——应用BootstrapTable表格插件

    1. 引言 之前的文章ABP入门系列(7)--分页实现讲解了如何进行分页展示,但其分页展示仅适用于前台web分页,在后台管理系统中并不适用.后台管理系统中的数据展示一般都是使用一些表格插件来完成的.这 ...

  3. ABP入门系列(5)——展现层实现增删改查

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 这一章节将通过完善Controller.View.ViewModel,来实现展现层的增删改查.最终 ...

  4. ABP入门系列(4)——创建应用服务

    ABP入门系列目录--学习Abp框架之实操演练 1. 解释下应用服务层 应用服务用于将领域(业务)逻辑暴露给展现层.展现层通过传入DTO(数据传输对象)参数来调用应用服务,而应用服务通过领域对象来执行 ...

  5. ABP入门系列(7)——分页实现_0

    ABP入门系列目录--学习Abp框架之实操演练 完成了任务清单的增删改查,咱们来讲一讲必不可少的的分页功能. 首先很庆幸ABP已经帮我们封装了分页实现,实在是贴心啊. 来来来,这一节咱们就来捋一捋如何 ...

  6. [置顶]ABP入门系列目录——学习Abp框架之实操演练

    本系列文章主要是基于ABP模板开发Mpa(多页面)『任务清单』项目. 由于是入门系列,不会用到代码生成器,每一行代码都是手动敲入. 源码已上传至Github-LearningMpaAbp,可自行参考. ...

  7. ABP入门系列(8)——Json格式化

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 讲完了分页功能,这一节我们先不急着实现新的功能.来简要介绍下Abp中Json的用法.为什么要在这一 ...

  8. ABP入门系列(6)——定义导航菜单

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 完成了增删改查以及页面展示,这一节我们来为任务清单添加[导航菜单]. 在以往的项目中,大家可能会手 ...

  9. abp.ajax get,ABP入门系列之Json格式化

    讲完了分页功能,这一节我们先不急着实现新的功能.来简要介绍下Abp中Json的用法.为什么要在这一节讲呢?当然是做铺垫啊,后面的系列文章会经常和Json这个东西打交道. 一.Json是干什么的 JSO ...

最新文章

  1. 这类程序员成华为宠儿,分分钟秒杀众应届毕业生
  2. R语言使用hexSticker包将ggplot2包可视化的结果转换为六角图(六角贴、六角形贴纸、ggplot2 plot to hex sticker)、并自定义设置文本的内容、文本对应的字体
  3. phpStudy在linux下的使用说明
  4. proe输入数字时成双出现_天猫双11花呗可提额,支付宝输入几个数字,试试就知道...
  5. Spark 编程模型(上)
  6. php把1拆分成三份,【php】位运算如何拆分
  7. 认识与入门 Markdown
  8. osgb转obj工具_在ArcGIS Pro中OSGB数据转换及发布服务流程
  9. 【报告分享】2022年快手新市井商业内循环营销通案:让企业经营走向确定性增长.pdf(附下载链接)...
  10. 【IO面试题】打印目录树形结构,并输出到file.txt中
  11. 海康nvr sdk java调用,海康SDK开发NVR拍照功能
  12. 全球时区 简称 缩写 简介 PST EST GMT CST EDT UTC 等
  13. 服务器显卡驱动重装系统,windows7旗舰版系统重装显卡驱动的方法
  14. 微信小程序实现图片虚化(滤镜)效果
  15. 武钢四中2021高考成绩查询,武汉市钢城四中怎么样 钢城四中介绍
  16. vs2017无法打开文件atls.lib问题
  17. 28个Github上最火的机器学习开源项目
  18. 外卖店优先级(模拟)
  19. 口语对话 谈判的基本技巧
  20. Java串口助手 带UI界面 Java串口调试工具 FPV

热门文章

  1. IOS web app一些实用的属性设置
  2. oracle中如何创建dblink
  3. ios sqlite3 初级应用
  4. [Bugku][Web][CTF] 9-15 write up
  5. 台达asda-b2伺服驱动器说明书_台达解决方案提升粉末冶金液压机的控制精度
  6. 清零 css,css样式清零及常用类
  7. 哈佛大学计算机科学专,哈佛大学计算机科学专业
  8. linux下anaconda3安装教程,Ubuntu18.04 安装 Anaconda3的教程详解
  9. js层级选择框样式_【JavaWeb】85:jQuery的各种选择器
  10. oracle禁止修改密码,Oracle 用户密码过期后不允许修改密码的示例代码