惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
爱范儿
爱范儿
P
Proofpoint News Feed
F
Fortinet All Blogs
雷峰网
雷峰网
小众软件
小众软件
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
S
Security @ Cisco Blogs
Help Net Security
Help Net Security
GbyAI
GbyAI
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
S
Security Affairs
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Help Net Security
O
OpenAI News
H
Hacker News: Front Page
博客园 - 叶小钗
Last Week in AI
Last Week in AI
S
Schneier on Security
The Last Watchdog
The Last Watchdog
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
MyScale Blog
MyScale Blog
Recorded Future
Recorded Future
博客园 - 【当耐特】
V
Vulnerabilities – Threatpost
大猫的无限游戏
大猫的无限游戏
N
News | PayPal Newsroom
The Hacker News
The Hacker News
A
Arctic Wolf

博客园 - 开发手游啦啦啦

用TypeScript开发爬虫程序 ABP导航源码分析 ABP的语言切换 AngularJs自定义指令详解(10) - 执行次序 AngularJs自定义指令详解(9) - terminal AngularJs自定义指令详解(8) - priority AngularJs自定义指令详解(7) - multiElement AngularJs自定义指令详解(6) - controller、require AngularJs自定义指令详解(5) - link AngularJs自定义指令详解(4) - transclude AngularJs自定义指令详解(3) - scope AngularJs自定义指令详解(2) - template AngularJs自定义指令详解(1) - restrict ABP的Zero Sample ABP的工作单元 ABP的数据过滤器(Data Filters) 初入Cocos2d-x 2.2 quick-cocos2d-x之testlua之VisibleRect.lua quick-cocos2d-x之testlua之mainMenu.lua
ABP的事件总线和领域事件(EventBus & Domain Events)
开发手游啦啦啦 · 2015-06-22 · via 博客园 - 开发手游啦啦啦

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.