ABP入门系列目录——学习Abp框架之实操演练

源码路径:Github-LearningMpaAbp


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

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

ABP入门系列(19)——使用领域事件的更多相关文章

  1. ABP入门系列(3)——领域层创建实体

    这一节我们主要和领域层打交道.首先我们要对ABP的体系结构以及从模板创建的解决方案进行一一对应.网上有代码生成器去简化我们这一步的任务,但是不建议初学者去使用. 一.首先来看看ABP体系结构 领域层就 ...

  2. ABP入门系列(18)—— 使用领域服务

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1.引言 自上次更新有一个多月了,发现越往下写,越不知如何去写.特别是当遇到DDD中一些概念术语的 ...

  3. ABP入门系列(2)——领域层创建实体

    ABP入门系列目录--学习Abp框架之实操演练 这一节我们主要和领域层打交道.首先我们要对ABP的体系结构以及从模板创建的解决方案进行一一对应.网上有代码生成器去简化我们这一步的任务,但是不建议初学者 ...

  4. ABP入门系列(4)——领域层定义仓储并实现

    一.先来介绍下仓储 仓储(Repository): 仓储用来操作数据库进行数据存取.仓储接口在领域层定义,而仓储的实现类应该写在基础设施层. 在ABP中,仓储类要实现IRepository接口,接口定 ...

  5. ABP入门系列(3)——领域层定义仓储并实现

    ABP入门系列目录--学习Abp框架之实操演练 一.先来介绍下仓储 仓储(Repository): 仓储用来操作数据库进行数据存取.仓储接口在领域层定义,而仓储的实现类应该写在基础设施层. 在ABP中 ...

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

    ABP是"ASP.NET Boilerplate Project (ASP.NET样板项目)"的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WE ...

  7. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

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

    这一章节将通过完善Controller.View.ViewModel,来实现展现层的增删改查.最终实现效果如下图: 一.定义Controller ABP对ASP.NET MVC Controllers ...

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

    一.解释下应用服务层 应用服务用于将领域(业务)逻辑暴露给展现层.展现层通过传入DTO(数据传输对象)参数来调用应用服务,而应用服务通过领域对象来执行相应的业务逻辑并且将DTO返回给展现层.因此,展现 ...

随机推荐

  1. Promise简介

    Promise是ES6中的函数,规范了如何处理异步任务的回调函数,功能类似于jQuery的defferred.简单说就是通过promise对象的不同状态调用不同的回调函数.目前IE8及以下不支持,其他 ...

  2. VHDL乘除法及转换

    首先鄙视一下这个不智能的语言 1.要进行乘法与除法,数据类型必须是signed 2.两个16位的数相乘,结果必须是32位的 3.乘以2的n次幂的数可以直接乘,之后截位也比较方便,(其实直接移位就可以) ...

  3. iOS面试题及答案

    设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情. 1). MVC模式:Model View Control,把模型 视图 控制器 ...

  4. 每天一道Java题[10]

    题目 阐述创建线程最常用的两种方法及其对比. 解答 方法一:继承Thread类实现 步骤: 创建Thread类的子类,如MyThread. 重写Thread类的run()方法. 实例化MyThread ...

  5. C/C++遍历目录下的所有文件(Windows篇,超详细)

    注: 1. 本文讨论的是怎么用Windows API遍历目录下的所有文件.除Windows API,还有一种Windows/Linux通用的方式,使用<io.h>. 2. 本文部分翻译自M ...

  6. INFORMATION_SCHEMA.PROFILING

    24.18 The INFORMATION_SCHEMA PROFILING Table PROFILING表提供了语句分析信息. 其内容对应于SHOW PROFILES和SHOW PROFILE语句 ...

  7. javaSE_Java第一周总结:有难度题目集合

    第一周练习总结 说明:尽量采用多种做法解决 1.使用三种方法实现变量交换 public class Test1Change{ public static void main(String[] args ...

  8. python List和String 转换注意

    不能用str(list),t=['\x87\xe9\xa5\xb0\xef\xbc']In [28]: str(t)Out[28]: "['\\x87\\xe9\\xa5\\xb0\\xef ...

  9. 用WebStorm创建Express项目时出现:express version is unavailable

    那是因为在npm的配置文件中使用了代理: 方式一:查看配置:npm config list如果有:registry = "https://registry.npm.taobao.org/&q ...

  10. 事件总线(Event Bus)知多少

    源码路径:Github-EventBus 简书同步链接 1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集 ...