ABP的事件總線和領域事件(EventBus & Domain Events)


http://www.aspnetboilerplate.com/Pages/Documents/EventBus-Domain-Events

EventBus

EventBus是個單例,獲得EventBus的引用可有下面兩個方法:

默認的EventBus實例,使用EventBus.Default即可找到它。
EventBus.Default.Trigger(...); //trigger an event

 

為單元測試考慮,更好的做法是通過依賴注入,獲得EventBus的引用,下面是通過屬性注入的代碼:

 

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

使用屬性注入比通過構造函數注入更好。上面代碼令EventBus初始化為 NullEventBus.Instance,跟ILogger一樣的做法。可以參考https://en.wikipedia.org/wiki/Null_Object_pattern對Null對象模式的詳細介紹。

 
自定義事件
 

讓事件類繼承於EventData:

 

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

EventData class defines EventSource (which object triggered the event) and EventTime(when it's triggered) properties.

 

EventData類定義了EventSource (觸發事件的源對象)和EventTime(何時觸發)屬性。

 
ABP已經定義好的事件

 

ASP.NET Boilerplate defines AbpHandledExceptionData and triggers this event when it automatically handles any exception. This is especially useful if you want to get more information about exceptions (even ASP.NET Boilerplate automatically logs all exceptions). You can register to this event to be informed when an exception occurs.

There are also generic event data classes for entity changes: EntityCreatedEventData<TEntity>, EntityUpdatedEventData<TEntity> and EntityDeletedEventData<TEntity>. They are defined in Abp.Events.Bus.Entities namespace. These events are automatically triggered by ASP.NET Boilerplate when an entity is inserted, updated or deleted. If you have a Person entity, can register to EntityCreatedEventData<Person> to be informed when a new Person created and inserted to database. These events also supports inheritance. If Student class derived from Person class and you registered to EntityCreatedEventData<Person>, you will be informed when a Person or Student inserted.

 

觸發事件

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});
    }
}

 

 
         

 

Trigger方法有幾個重載:

 

 
         

 

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)

 

處理事件

需要實現 IEventHandler<T>

 

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

EventBus is integrated with dependency injection system. As we implemented ITransientDependency above, when a TaskCompleted event occured, it creates a new instance of ActivityWriter class and calls it's HandleEvent method, then disposes it. See dependency injection for more.

 

處理單個事件

Eventbus支持事件的繼承:

 

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; }
}

 

在事件處理類里對事件子類進行判斷即可:

 

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

 

同時處理多個事件

一個事件處理類就可以同時處理多個事件,只需要實現多個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會自動掃描事件處理類,在事件觸發時自動使用依賴注入來取得處理器對象來處理事件,並在最后釋放處理器對象。

 
手動注冊
手動注冊一般不會用到,這里就不翻譯了。

 

It is also possible to manually register to events but use it with caution. In a web application, event registration should be done at application start. It's not a good approach to register to an event in a web request since registered classes remain registered after request completion and keep re-registering for each request. This may cause problems for your application since registered class can be called multiple times. Also keep in mind that manual registration does not use dependency injection system.

There are some overloads of register method of the event bus. The simplest one waits a delegate (or a lambda):

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

Thus, then a 'task completed' event occurs, this lambda method is called. Second one waits an object that implements IEventHandler<T>:

EventBus.Register<TaskCompletedEventData>(new ActivityWriter());

Same instance ıf ActivityWriter is called for events. This method has also a non-generic overload. Another overload accepts two generic arguments:

EventBus.Register<TaskCompletedEventData, ActivityWriter>();

In this time, event bus created a new ActivityWriter for each event. It calls ActivityWriter.Dispose method if it's disposable.

Lastly, you can register a event handler factory to handle creation of handlers. A handler factory has two methods: GetHandler and ReleaseHandler. Example:

public class ActivityWriterFactory : IEventHandlerFactory
{
    public IEventHandler GetHandler()
    {
        return new ActivityWriter();
    }

    public void ReleaseHandler(IEventHandler handler)
    {
        //TODO: release/dispose the activity writer instance (handler)
    }
}

There is also a special factory class, the IocHandlerFactory, that can be used to use dependency injection system to create/release handlers. ASP.NET Boilerplate also uses this class in automatic registration mode. So, if you want to use dependency injection system, directly use automatic registration.

 

取消注冊

手動注冊后,可能還有手動取消注冊的需求,這個也不翻譯了。

 

When you manually register to event bus, you may want to unregister to the event later. Simplest way of unregistering an event is disposing the return value of theRegister method. Example:

//Register to an event...
var registration = EventBus.Register<TaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId) );

//Unregister from event
registration.Dispose();

Surely, unregistration will be somewhere and sometime else. Keep registration object and dispose it when you want to unregister. All overloads of the Register method returns a disposable object to unregister to the event.

EventBus also provides Unregister method. Example usage:

//Create a handler
var handler = new ActivityWriter();
            
//Register to the event
EventBus.Register<TaskCompletedEventData>(handler);

//Unregister from event
EventBus.Unregister<TaskCompletedEventData>(handler);

It also provides overloads to unregister delegates and factories. Unregistering handler object must be the same object which is registered before.

Lastly, EventBus provides a UnregisterAll<T>() method to unregister all handlers of an event and UnregisterAll() method to unregister all handlers of all events.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM