1 前置阅读

在阅读本文章之前,你可以先阅读:

  • DDD领域驱动设计是什么
  • DDD领域驱动设计:实体、值对象、聚合根
  • DDD领域驱动设计:仓储
  • MediatR一个优秀的.NET中介者框架

2 什么是领域事件?

领域事件是在领域中发生的事,你希望同一个领域(进程)的其他部分了解它。 通知部分通常以某种方式对事件作出反应。

3 实现领域事件?

重点强调领域事件发布/订阅是使用 MediatR 同步实现的。

首先,定义待办事项已更新的领域事件

public class TodoUpdatedDomainEvent : INotification
{
public Todo Todo { get; } public TodoUpdatedDomainEvent(Todo todo)
{
Todo = todo;
}
}

然后,引发领域事件,将域事件添加到集合,然后在提交事务之前或之后立即调度这些域事件,而不是立即调度到域事件处理程序 。

public abstract class Entity
{
//...
private List<INotification> domainEvents;
public IReadOnlyCollection<INotification> DomainEvents => domainEvents?.AsReadOnly(); public void AddDomainEvent(INotification eventItem)
{
domainEvents = domainEvents ?? new List<INotification>();
domainEvents.Add(eventItem);
} public void RemoveDomainEvent(INotification eventItem)
{
domainEvents?.Remove(eventItem);
} public void ClearDomainEvents()
{
domainEvents?.Clear();
}
//... 其他代码
}

要引发事件时,只需将其在聚合根实体的方法处添加到代码中的事件集合。

public class Todo : AggregateRoot
{
//...
public void Update(
string name)
{
Name = name;
AddDomainEvent(new TodoUpdatedDomainEvent(this));
}
//... 其他代码
}

请注意 AddDomainEvent 方法的唯一功能是将事件添加到列表。 尚未调度任何事件,尚未调用任何事件处理程序。你需要在稍后将事务提交到数据库时调度事件。

public class Repository : IDisposable, IRepository
{
//...
private readonly IMediator mediator;
private readonly DbContext context; public Repository(DbContext context, IMediator mediator)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
this.mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
} public void Save()
{
mediator.DispatchDomainEvents(context);
context.SaveChanges();
} public static void DispatchDomainEvents(this IMediator mediator, DbContext ctx)
{
var domainEntities = ctx.ChangeTracker
.Entries<Entity>()
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()); var domainEvents = domainEntities
.SelectMany(x => x.Entity.DomainEvents)
.ToList(); domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents()); foreach (var domainEvent in domainEvents)
mediator.Publish(domainEvent);
}
//... 其他代码
}

最后,订阅并处理领域事件

public class TodoUpdatedDomainEventHandler : INotificationHandler<TodoUpdatedDomainEvent>
{
private readonly ILoggerFactory logger;
public TodoUpdatedDomainEventHandler(ILoggerFactory logger)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
} public Task Handle(TodoUpdatedDomainEvent todoUpdatedDomainEvent, CancellationToken cancellationToken)
{
logger.CreateLogger<TodoUpdatedDomainEvent>().LogDebug("Todo with Id: {TodoId} has been successfully updated",
todoUpdatedDomainEvent.Todo.Id);
return Task.CompletedTask;
}
}

DDD领域驱动设计:领域事件的更多相关文章

  1. 领域驱动设计和Spring

    原文 http://static.olivergierke.de/lectures/ddd-and-spring/ 1.介绍这篇文章是的介绍一下领域驱动设计的基础构件.概念和Java的web应用(主要 ...

  2. 如何使用ABP进行软件开发(2) 领域驱动设计和三层架构的对比

    简述 上一篇简述了ABP框架中的一些基础理论,包括ABP前后端项目的分层结构,以及后端项目中涉及到的知识点,例如DTO,应用服务层,整洁架构,领域对象(如实体,聚合,值对象)等. 笔者也曾经提到,AB ...

  3. 基于“事件”驱动的领域驱动设计(DDD)框架分析

    摘抄自 从去年10月份开始,学了几个月的领域驱动设计(Domain Driven Design,简称DDD).主要是学习领域驱动设计之父Eric Evans的名著:<Domain-driven ...

  4. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  5. DDD 领域驱动设计-商品建模之路

    最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...

  6. DDD 领域驱动设计-如何控制业务流程?

    上一篇:<DDD 领域驱动设计-如何完善 Domain Model(领域模型)?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sa ...

  7. [转]DDD领域驱动设计基本理论知识总结

    领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity i ...

  8. 领域驱动设计(DDD)部分核心概念的个人理解

    领域驱动设计(DDD)是一种基于模型驱动的软件设计方式.它以领域为核心,分析领域中的问题,通过建立一个领域模型来有效的解决领域中的核心的复杂问题.Eric Ivans为领域驱动设计提出了大量的最佳实践 ...

  9. DDD领域驱动设计之领域服务

    1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 什么是领域服务,DDD书中是说,有些类或者方法,放实体A也不好,放实体B ...

随机推荐

  1. 在wildfly 21中搭建cluster集群

    目录 简介 下载软件和相关组件 配置domain 创建应用程序 部署应用程序 集群配置 总结 简介 wildfly是一个非常强大的工具,我们可以轻松的使用wildfly部署应用程序,更为强大的是,wi ...

  2. Qt学习笔记-更高级的文本编辑器-完善第一版-gif动画

    现在的浏览器大多都有动作图标,现在我们也为浏览器加上图标. 在网上搜索到了几个ico的图标.现在直接拿来用. 首先创建资源文件. 在工程名上鼠标右键,选择add new 然后再选择 Qt Resour ...

  3. mysql explain参数详解

    主要对几个参数做一些记录 type:显示的是访问类型 从最好到最差的连接类型为:const.eq_reg.ref.range.index和ALL 至少要达到range,基本是ref  最好是const ...

  4. java中byte,byte[]和int之间的转换

    1>byte类型转换为,直接隐式转换,适用于要求保持数值不变,例如要求进行数值计算 如 byte b=0x01; int i=b; 2>另一种是要求保持最低字节中各个位不变,3个高字节全部 ...

  5. [每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?

    关注「松宝写代码」,精选好文,每日一题 ​时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  6. Ubuntu/Liinux睡眠无法唤醒解决方法:ACPI设置

    最近给笔记本换了一个固态,顺便就重装了一下系统,版本是Ubuntu 20.10.装完之后各种功能基本都是正常的,触摸板轻触单击.双指右键等功能开箱即用.但是在安装完最新的Nvidia驱动之后就出现了问 ...

  7. 项目API接口鉴权流程总结

    权益需求对接中,公司跟第三方公司合作,有时我们可能作为甲方,提供接口给对方,有时我们也作为乙方,调对方接口,这就需要API使用签名方法(Sign)对接口进行鉴权.每一次请求都需要在请求中包含签名信息, ...

  8. Faceto_object_programdesign

    一面向对象程序设计思想 1 和面向过程关注点不同 过程: 程序执行流程和逻辑 (局部功能) 对象: 程序中的对象 (程序结构) 2 对象 现实世界中的实体和事物 可以看成是一种具有自身属性和功能的构件 ...

  9. JVM 源码分析(二):搭建 JDK 8 源码调试环境(Windows 上使用 CLion)

    前言 一.准备源码 二.安装 "Bootstrap JDK" 三.配置编译环境 四.编译与测试 五.安装 CMake 和 GDB 五.准备远程调试 六.开始远程调试 前言 上一篇文 ...

  10. php 去除路由中index.php 通过 .htaccess 文件

    首先在入口文件index.php得的当前目录下 创建 .htaccess文件. 然后将下面一段代码放进去: <IfModule mod_rewrite.c> RewriteEngine o ...