• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    详解ABP框架中领域层的领域事件Domain events

    在C#中,一个类可以定义其专属的事件并且其它类可以注册该事件并监听,当事件被触发时可以获得事件通知。这对于对于桌面应用程序或独立的Windows Service来说非常有用。但是, 对于Web应用程序来说会有点问题,因为对象是根据请求(request)被创建并且它们的生命周期都很短暂。我们很难注册其它类别的事件。同样地,直接注册其它类别的事件也造成了类之间的耦合性。

    在应用系统中,领域事件被用于解耦并且重用(re-use)商业逻辑。

    事件总线
    事件总线为一个单体(singleton)的对象,它由所有其它类所共享,可通过它触发和处理事件。要使用这个事件总线,你需要引用它。你可以用两种方式来实现:

    获取默认实例( Getting the default instance)

    你可以直接使用EventBus.Default。它是全局事件总线并且可以如下方式使用:

    EventBus.Default.Trigger(...); //触发事件
    

    注入IEventBus事件接口(Injecting IEventBus)

    除了直接使用EventBus.Default外,你还可以使用依赖注入(DI)的方式来取得IEventBus的参考。这利于进行单元测试。在这里,我们使用属性注入的范式:

     public class TaskAppService : ApplicaService {
      public IEventBus EventBus { get; set; }
      public TaskAppService() {
       EventBus = NullEventBus.Instance;
      }
     }
    

    注入事件总线,采用属性注入比建构子注入更适合。事件是由类所描述并且该事件对象继承自EventData。假设我们想要触发某个事件于某个任务完成后:

     public class TaskCompletedEventData : EventData {
      public int TaskId { get; set; }
     }
    

    这个类所包含的属性都是类在处理事件时所需要的。EventData类定义了EventSource(那个对象触发了这个事件)和EventTime(何时触发)属性。

    定义事件
    ABP定义AbpHandledExceptionData事件并且在异常发生的时候自动地触发这个事件。这在你想要取得更多关于异常的信息时特别有用(即便ABP已自动地纪录所有的异常)。你可以注册这个事件并且设定它的触发时机是在异常发生的时候。

    ABP也提供在实体变更方面许多的通用事件数据类: EntityCreatedEventData, EntityUpdatedEventData和EntityDeletedEventData。它们被定义在Abp.Events.Bus.Entitis命名空间中。当某个实体新增/更新/删除后,这些事件会由ABP自动地触发。如果你有一个Person实体,可以注册到EntityCreatedEventData,事件会在新的Person实体创建且插入到数据库后被触发。这些事件也支持继承。如果Student类继承自Person类,并且你注册到EntityCreatedEventData中,接着你将会在Person或Student新增后收到触发。

    触发事件
    触发事件的范例如下:

     public class TaskAppService : ApplicationService {
      public IEventBus EventBus { get; set; }
      public TaskAppService() {
       EventBus = NullEventBus.Instance;
      }
    
      public void CompleteTask(CompleteTaskInput input) {
       //TODO: 已完成数据库上的任务
       EventBus.Trigger(new TaskCompletedEventData { TaskId = 42 } );
      }
     }
    

    这里有一些触发方法的重载:

     EventBus.TriggerTaskcompletedEventData>(new TaskCompletedEventData { TaskId = 42});
     EventBus.Trigger(this, new TaskCompletedEventData { TaskId = 42 });
     EventBus.Trigger(typeof(TaskCompletedEventData), this, new TaskCompletedEventData { TaskId = 42});
    

    事件处理
    要进行事件的处理,你应该要实现IEventHandler接口如下所示:

     public class ActivityWriter : IEventHandlerTaskCompletedEventData>, ITransientDependency {
      public void HandleEvent(TaskCompletedEventData eventData) {
       WriteActivity("A task is completed by id = " + eventData.TaskId);
      }
     }
    

    EventBus已集成到依赖注入系统中。就如同我们在上例中实现ITransientDependency那样,当TaskCompleted事件触发,它会创建一个新的ActivityWriter类的实体并且调用它的HandleEvent方法,并接着释放它。详情请见依赖注入(DI)一文。

    1.基础事件的处理(Handling base events)

     EventBus支持事件的继承。举例来说,你可以创建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来处理这两个事件:

     public class ActivityWriter : IEventHandlerTaskEventData>, ITransientDependency {
      public void HandleEvent(TaskEventData eventData) {
       if(eventData is TaskCreatedEventData) {
       ...
       }else{
       ...
       }
      }
     }
    

    当然,你也可以实现IEventHandler来处理所有的事件,如果你真的想要这样做的话(译者注:作者不太建议这种方式)。

    2.处理多个事件(Handling multiple events)

    在单个处理器(handler)中我们可以可以处理多个事件。此时,你应该针对不同事件实现IEventHandler。范例如下:

     public class ActivityWriter :
      IEventHandlerTaskCompletedEventData>,
      IEventHandlerTaskCreatedEventData>,
      ITransientDependency
     {
      public void HandleEvent(TaskCompletedEventData eventData) {
       //TODO: 处理事件
      }
      public void HandleEvent(TaskCreatedEventData eventData) {
       //TODO: 处理事件
      }
     }
    

    注册处理器
    我们必需注册处理器(handler)到事件总线中来处理事件。

    1.自动型Automatically

    ABP扫描所有实现IEventHandler接口的类,并且自动注册它们到事件总线中。当事件发生, 它通过依赖注入(DI)来取得处理器(handler)的引用对象并且在事件处理完毕之后将其释放。这是比较建议的事件总线使用方式于ABP中。

    2.手动型(Manually)

    也可以通过手动注册事件的方式,但是会有些问题。在Web应用程序中,事件的注册应该要在应用程序启动的时候。当一个Web请求(request)抵达时进行事件的注册,并且反复这个行为。这可能会导致你的应用程序发生一些问题,因为注册的类可以被调用多次。同样需要注意的是,手动注册无法与依赖注入系统一起使用。

    ABP提供了多个事件总线注册方法的重载(overload)。最简单的一个重载方法是等待委派(delegate)或Lambda。

     EventBus.RegisterTaskCompletedEventData>(eventData =>
      {
       WriteActivity("A task is completed by id = " + eventData.TaskId);
      });
    

    因此,事件:task completed会发生,而这个Lambda方法会被调用。第二个重载方法等待的是一个对象,该对象实现了IEventHandler:

    Eventbus.RegisterTaskCompletedEventData>(new ActivityWriter());
    

    相同的例子,如果ActivityWriter因事件而被调用。这个方法也有一个非泛型的重载。另一个重载接受两个泛化的参数:

    EventBus.RegisterTaskCompletedEventData, ActivityWriter>();
    此时,事件总线创建一个新的ActivityWriter于每个事件。当它释放的时候,它会调用ActivityWriter.Dispose方法。

    最后,你可以注册一个事件处理器工厂(event handler factory)来负责创建处理器。处理器工厂有两个方法: GetHandler和ReleaseHandler,范例如下:

    public class ActivityWriterFactory : IEventHandlerFactory {
      public IEventHandler GetHandler() {
       return new ActivityWriter();
      }
      public void ReleaseHandler(IEventHandler handler) {
       //TODO: 释放ActivityWriter实体(处理器)
      }
     }
    

    ABP也提供了特殊的工厂类,IocHandlerFactory,通过依赖注入系统,IocHandlerFactory可以用来创建或者释放(dispose)处理器。ABP可以自动化注册IocHandlerFactory。因此,如果你想要使用依赖注入系统,请直接使用自动化注册的方式。

    取消注册事件
    当你手动注册事件总线,你或许想要在之后取消注册。最简单的取消事件注册的方式即为registration.Dispose()。举例如下:

    //注册一个事件
    Var registration = EventBus.RegisterTaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId));
    //取消注册一个事件
    registration.Dispose();
    

    当然,取消注册可以在任何地方任何时候进行。保存(keep)好注册的对象并且在你想要取消注册的时候释放(dispose)掉它。所有注册方法的重载(overload)都会返回一个可释放(disposable)的对象来取消事件的注册。

    事件总线也提供取消注册方法。使用范例:

    //创建一个处理器
    var handler = new ActivityWriter();
    //注册一个事件
    EventBus.RegisterTaskCompletedEventData>(handler);
    //取消这个事件的注册
    EventBus.UnregisterTaskCompletedEventData>(handler);
    

    它也提供重载的方法给取消注册的委派和工厂。取消注册处理器对象必须与之前注册的对象是同一个。

    最后,EventBus提供一个UnregisterAll()方法来取消某个事件所有处理器的注册,而UnregisterAll()方法则是所有事件的所有处理器。

    您可能感兴趣的文章:
    • 解析ABP框架中的数据传输对象与应用服务
    • ABP框架中的日志功能完全解析
    • 详解ABP框架的参数有效性验证和权限验证
    • 解析ABP框架中的事务处理和工作单元
    • 详解ABP框架中的数据过滤器与数据传输对象的使用
    • 解析ABP框架领域层中的实体类与仓储类
    • 详解ABP框架中Session功能的使用方法
    • 详解ABP框架中的日志管理和设置管理的基本配置
    • ABP框架的基础配置及依赖注入讲解
    • ABP框架的体系结构及模块系统讲解
    • ASP.NET样板项目ABP框架的特性总结
    • 基于ASP.NET MVC的ABP框架入门学习教程
    • ABP框架中导航菜单的使用及JavaScript API获取菜单的方法
    上一篇:解析ABP框架中的事务处理和工作单元
    下一篇:ASP.NET(C#) Web Api通过文件流下载文件的实例
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    详解ABP框架中领域层的领域事件Domain events 详解,ABP,框架,中,领域,层,