ABP官方文档翻译 3.7 领域事件(事件总线)
领域事件(事件总线)
- 事件总线
- 注入IEventBus
- 获取默认实例
- 定义事件
- 预定义事件
- 处理异常
- 实体更改
- 预定义事件
- 触发事件
- 处理事件
- 处理基础事件
- 处理者异常
- 处理多个事件
- 注册处理者
- 自动
- 手动
- 取消注册
在C#中,一个类可以定义自己的事件,其他类可以注册它以便当一些事情发生时就会被通知。对于桌面应用或者单独的windows服务而言,这是非常有用的。但是,对于Web应用,会有一点儿问题,因为对象在web请求中被创建并且是短暂存在的。注册类事件非常困难。直接注册另一个类的事件会使类变得紧耦合。
在应用中,领域事件可以用来解耦业务逻辑且能够反应重要的领域更改。
事件总线
事件总线是一个单例对象,被其他所有的类共享来触发和处理事件。为了使用事件总线,你需要获取一个它的引用。可以使用两种方式来获取。
注入IEventBus
你可以使用依赖注入获取IEventBus的引用。这里,我们使用属性注入模式:
public class TaskAppService : ApplicationService {public IEventBus EventBus { get; set; }public TaskAppService(){EventBus = NullEventBus.Instance;} }
属性注入比构造函数注入更加适合注入事件总线。因此,你的类没有事件总线也可以正常工作。NullEventBus实现了空对象模式。当你调用它的方法时,它什么也不做。
获取默认实例
如果你不能注入它的话,你可以直接使用EventBus.Default。它是全局的时间总线且可以按如下所示使用:
EventBus.Default.Trigger(...); //trigger an event
不建议直接使用EventBus.Default,因为它使单元测试变得困难。
定义事件
在触发事件之前,你应该首先定义这个事件。事件以类的形式呈现,这个类集成自EventData。假定,当一个任务完成时我们想触发一个事件:
public class TaskCompletedEventData : EventData {public int TaskId { get; set; } }
这个类包含处理事件类所需要的属性。EventData类定义了EventSource(哪一个对象触发这个事件)和EventTime(什么时候触发)属性。
预定义事件
处理异常
ABP定义了AbpHandledExceptionData,当ABP自动处理任何异常时会触发这个事件。当你想获取关于异常的更多信息时(甚至ABP自动记录所有的异常),这个会特别有用。你可以注册这个事件,当异常发生时便会被通知。
实体更改
实体变更也有通用的事件数据类。EntityCreatingEventData<TEntity>、EntityCreatedEventData<TEntity>、EntityUpdatingEventData<TEntity>、EntityUpdatedEventData<TEntity>、ENtityDeletingEventData<TEntity>和EntityDeletedEventData<TEntity>。还有EntityChangingEventData<TEntity>和EntityChangedEventData<TEntity>。更改可以插入、更新和删除。
‘ing’事件(例如:EntityUpdating)在保存更改之前触发。所以你可以通过在这些事件中抛出异常来回滚工作单元以阻止操作。‘ed’事件(例如:EntityUpdated)在保存更改之后发生,这时就没有机会回滚工作单元了。
实体更改事件在Abp.Events.Bus.Entities命名空间中定义,当一个实体被插入、更新或删除时,ABP自动触发。如果你有一个Person实体,可以注册到EntityCreatedEvnetData<Person>,当一个新Person被创建并插入到数据库时会接收到通知。这些事件支持继承。如果Student类继承自Person类且注册到EntityCreatedEventData<Person>,当一个Person或Student被插入时就会收到通知。
触发事件
触发事件比较简单:
public class TaskAppService : ApplicationService {public IEventBus EventBus { get; set; }public TaskAppService(){EventBus = NullEventBus.Instance;}public void CompleteTask(CompleteTaskInput input){//TODO: complete the task on database...EventBus.Trigger(new TaskCompletedEventData {TaskId = 42});} }
这有一些触发方法的重载版本:
EventBus.Trigger<TaskCompletedEventData>(new TaskCompletedEventData { TaskId = 42 }); //Explicitly declare generic argument EventBus.Trigger(this, new TaskCompletedEventData { TaskId = 42 }); //Set 'event source' as 'this' EventBus.Trigger(typeof(TaskCompletedEventData), this, new TaskCompletedEventData { TaskId = 42 }); //Call non-generic version (first argument is the type of the event class)
另一种触发事件的方式是使用聚合根的领域事件集合。(在Entity documentation中查看相关部分)
处理事件
为了处理事件,你应该实现IEventHandler<T>接口,如下所示:
public class ActivityWriter : IEventHandler<TaskCompletedEventData>, ITransientDependency {public void HandleEvent(TaskCompletedEventData eventData){WriteActivity("A task is completed by id = " + eventData.TaskId);} }
IEventHandler定义了HandleEvent方法,我们按如上所示实现它。
事件总线集成到了依赖注入系统。如我们上面实现的ITransientDependency,当一个TaskCompleted事件发生时,它创建一个ActivityWriter类的新实例,并调用它的HandleEvent方法,然后释放他。参见依赖注入了解更多。
处理基础事件
事件总线支持事件继承。例如,你创建了一个TaskEventData和两个继承类:TaskCompletedEventData和TaskCreatedEventData:
public class TaskEventData : EventData {public Task Task { get; set; } }public class TaskCreatedEventData : TaskEventData {public User CreatorUser { get; set; } }public class TaskCompletedEventData : TaskEventData {public User CompletorUser { get; set; } }
然后,你可以实现IEventHandler<TaskEventData>处理这两个事件:
public class ActivityWriter : IEventHandler<TaskEventData>, ITransientDependency {public void HandleEvent(TaskEventData eventData){if (eventData is TaskCreatedEventData){//... }else if (eventData is TaskCompletedEventData){//... }} }
这也意味着你可以实现IEventHandler<EventData>处理应用中的所有事件。你或许不希望这样,但是这是可以实现的。
处理者异常
事件总线触发所有的处理者,即使他们中的一个或一些抛出异常。如果他们中的一个抛出异常,然后他被触发方法直接抛出。如果多余一个处理者抛出异常,事件总线会抛出他们的一个聚合异常。
处理多个事件
你可以在一个处理者中处理多个事件。这时,你应该为每一个事件实现IEventHandler<T>。示例:
public class ActivityWriter : IEventHandler<TaskCompletedEventData>, IEventHandler<TaskCreatedEventData>, ITransientDependency {public void HandleEvent(TaskCompletedEventData eventData){//TODO: handle the event... }public void HandleEvent(TaskCreatedEventData eventData){//TODO: handle the event... } }
注册处理者
我们必须注册处理者到事件总线,以便能够处理事件。
自动
ABP查找所有实现IEventHandler的类,并注册的依赖注入(例如,如上面示例所示的实现ITransientDependency)。然后,它自动注册他们到事件总线。当一个事件发生时,它使用依赖注入得到处理者的一个引用,并在处理事件之后释放处理者。在ABP中,推荐使用这种方式使用事件总线。
手动
手动注册也是可以的,但需要小心。在web应用中,事件注册需要在应用开始时完成。在一个web请求中注册一个事件不是一个好方式,因为被注册的类在请求结束后仍然保持被注册状态,且为每一次请求重新注册。这会导致你的应用出现问题,因为注册类会被调用多次。还要记得,手动注册不使用依赖注入系统。
这有一些事件总线注册方法的重载。最简单一个接收一个委托(或拉姆达表达式):
EventBus.Register<TaskCompletedEventData>(eventData =>{WriteActivity("A task is completed by id = " + eventData.TaskId);});
因此当一个'task completed'事件发生时,会调用这个拉姆达表达式。第二个接收一个实现了IEventHandler<T>接口的对象:
EventBus.Register<TaskCompletedEventData>(new ActivityWriter());
多个事件会调用同一个ActivityWriter实例。这个方法有一个非泛型的重载版本。另一个重载接收两个泛型参数:
EventBus.Register<TaskCompletedEventData, ActivityWriter>();
这次,事件总线为每个事件创建一个ActivityWriter实例。如果它是一次性处理的,它将调用ActivityWriter.Dispose方法。
最后,你可以注册一个事件处理者工厂来处理处理者的创建。一个处理者工厂有两个方法:GetHandler和Releasehandler。例如:
public class ActivityWriterFactory : IEventHandlerFactory {public IEventHandler GetHandler(){return new ActivityWriter();}public void ReleaseHandler(IEventHandler handler){//TODO: release/dispose the activity writer instance (handler) } }
这有一个特殊工厂类,IocHandlerFactory,可以用来使用依赖注入系统创建或释放处理者。ABP也使用这个类来实现自动注册。所以,如果你想使用依赖注入系统,直接使用之前定义的自动注册。
取消注册
当你手动注册事件总线,你或许想稍后取消注册这个事件。取消注册事件的最简单方式是释放注册方法的返回值。示例:
//Register to an event... var registration = EventBus.Register<TaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId) );//Unregister from event registration.Dispose();
当然,取消注册可能在其他地方或其他时间。保留注册对象并当你想取消注册时释放它。注册方法的所有重载都返回一个可释放对象用来取消注册事件。
事件总线也提供了Unregister方法。示例用法:
//Create a handler var handler = new ActivityWriter();//Register to the event EventBus.Register<TaskCompletedEventData>(handler);//Unregister from event EventBus.Unregister<TaskCompletedEventData>(handler);
它也提供了重载来取消注册委托和工厂。取消注册处理者对象必须是之前注册的同一个对象。
最后,事件总线提供了一个UnregisterAll<T>方法用来取消注册一个事件的所有处理者和UnregisterAll()方法用来取消所有事件的所有注册者。
返回主目录
转载于:https://www.cnblogs.com/xajh/p/6875632.html
ABP官方文档翻译 3.7 领域事件(事件总线)相关推荐
- ABP官方文档翻译 0.0 ABP官方文档翻译目录
一直想学习ABP,但囿于工作比较忙,没有合适的契机,当然最重要的还是自己懒.不知不觉从毕业到参加工作七年了,没留下点儿什么,总感觉很遗憾,所以今天终于卯足劲鼓起勇气开始写博客.有些事能做的很好,但要跟 ...
- ABP官方文档翻译 3.1 实体
实体 实体类 聚合根类 领域事件 常规接口 审计 软删除 激活/失活实体 实体改变事件 IEntity接口 实体是DDD(领域驱动设计)的核心概念之一.Eric Evans描述它为"An o ...
- ABP官方文档翻译 1.2 N层架构
N层架构 介绍 ABP架构 其他(通用) 领域层 应用层 基础设施层 网络和展现层 其他 总结 介绍 应用程序代码库的分层架构是被广泛认可的可以减少程序复杂度.提高代码复用率的技术.为了实现分层架构, ...
- ABP官方文档翻译 6.1.3 异常处理
处理异常 介绍 启用错误处理 Non-Ajax请求 显示异常 UserFriendlyException Error模型 AJAX请求 异常事件 介绍 此文档是与ASP.NET MVC和Web API ...
- ABP官方文档翻译 4.6 审计日志
审计日志 介绍 关于IAuditingStore 配置 通过特性启用/禁用 注意事项 介绍 维基百科:"审计追踪(也称为审计日志)是与安全相关的按时间先后的记录.记录集合.记录的目的地和源, ...
- ABP官方文档翻译 6.3 本地化
本地化 介绍 应用程序语言 本地化源 XML文件 注册XML本地化源 JSON文件 注册JSON本地化源 资源文件 自定义源 当前语言是如何决定的 ASP.NET Core ASP.NET MVC 5 ...
- ABP官方文档翻译 6.1.2 MVC视图
ASP.NET MVC 视图 介绍 AbpWebViewPage基类 介绍 ABP通过Abp.Web.Mvc nuget包集成到MVC视图.你可以如往常一样创建正常的MVC视图. AbpWebView ...
- ABP官方文档翻译 9.2 Entity Framework Core
Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...
- ABP官方文档翻译 6.1.1 MVC控制器
ASP.NET MVC控制器 介绍 AbpController基类 本地化 其他 过滤器 异常处理和结果包装 审计日志 验证 授权 工作单元 介绍 ABP通过Abp.Web.Mvc nuget包集成到 ...
最新文章
- 华为+长安研发芯片?长安蔚来更名“阿维塔科技”
- Visual studio 2005如何实现源码管理
- 第二十五课.元学习MetaLearning
- python官方手册-Python3 中文手册
- 用HTML制作一个漂亮的成绩表,JS-结合html综合练习js的对象——班级成绩表制作...
- Ookla speedtest网速测试算法实现
- MySql like 查询 变向写法(不用like 完成like查询)
- 它估值 25 亿!被马云领投,是华为“老战友”,网友:也许股价能超茅台!
- RPC框架设计概要-性能
- 论模式在领域驱动设计中的重要性
- [Cocos Creator] 制作简版消消乐(四):实现消除算法
- python Excel公式
- 针对ewebeditor编辑器漏洞一次实战经验
- “第二课堂”开课啦~
- 对圆柱面的曲面积分_积分曲面为圆柱面的曲面积分的计算
- ps、firewords在win78中无法直接拖入的问题解决方法
- Win自动配置VS Code的C++开发环境
- 终极孵化器:仿生婴儿的美丽新世界
- ConViT:使用软卷积归纳偏置改进视觉变换器
- 详解Android电量优化
热门文章
- arm linux输出到lcd,求助 armlinux中实现lcd显示
- HTML快速上手教程
- tar 打包、压缩和备份
- 国外软件测试方法,ATE软件测试方法研究及实现
- axure9数据统计插件_数据分析太棘手?常用8大统计软件解决难题!
- python histogram函数_python (ploit2)(histogram)
- 地磅称重软件源码_地磅称重软件需求梳理的重要性
- fread读取同一个文件得到缓冲区大小不同_c++日志文件操作
- PDE11 wave equation: d'Alembert examples
- 无人机图像深度学习的大豆害虫检测与分类