<ABP framework> domain events (EvnetBus), abpevnetbus
Document directory
Content of this section:
- EventBus
- Inject IEventBus
- Get default instance
- Define events
- Predefined events
- Exception after processing
- Entity Modification
- Trigger event
- Event handling
- Process basic events
- Handler exception
- Process multiple events
- Handler Registration
- Anti-registration
In C #, a class can define its own event, and other classes can register it to receive notifications when something happens. This is very useful for desktop applications or stand-alone Windows Services. However, for a Web application, it is a bit problematic because the objects are created in a web request and their lifecycles are short. Therefore, it is difficult to register some class events. At the same time, registering another class event directly makes the classes more compatible.
Domain events are generally used to parse business logic and send notifications when important domain changes occur in applications.
EventBus
EventBus is a singleton object that is shared when all classes trigger events or process events. To use the event bus, you must first reference it in two ways.
Inject IEventBus
You can use dependency injection to obtain an IEventBus reference. Here we use the attribute injection mode:
public class TaskAppService : ApplicationService{ public IEventBus EventBus { get; set; } public TaskAppService() { EventBus = NullEventBus.Instance; }}
Property injection is more suitable than constructor injection on the injection event bus. Your class can have no event bus. NullEventBus implements the empty object mode. When you call its method, nothing is done in the method.
Get default instance
If you cannot inject it, You can directly use EventBus. Default. It is a global event bus and is used as follows:
EventBus.Default.Trigger(...); //trigger an event
It is not recommended to use EventBus. Default directly wherever possible because it is difficult to perform unit testing.
Define events
Before triggering an event, you must first define it and present an event through a class inherited from EventData. Suppose we want to trigger an event after a task is completed:
public class TaskCompletedEventData : EventData{ public int TaskId { get; set; }}
This class contains the attributes required to process the event class. The EventData class defines the EventSource (event source, which object triggers the event) and EventTime (when the event is triggered) attributes.
Predefined events
ProcessedException
ABC defines AbpHandledExceptionData, and this event is triggered when it automatically handles any exceptions, this is especially useful when you want to learn more about exceptions (even though ABC automatically records all exceptions ). You can register this event and send a notification when an exception occurs.
Entity Modification
Provides generic events for entity modification: EntityCreationEventData <Tentity>, entity <TEntity>, EntityUpdatingEventData <TEntity>, entity <TEntity>, EntityDeletingEventData <TEntity>, and entity <TEntity>, there are also EntityChangingEventData <TEntity> and EntityChangedEventData <TEntity>, which can be inserted, updated, or deleted.
"Ing" events (such as EntityUpdating) are triggered before saving the changes (SaveChanges). Therefore, you can throw an exception in these events to urge the work unit to roll back and block operations ). The "ed" event (for example, EntityUpdated) is triggered after the modification is saved, so there is no chance to roll back the work unit.
The object modification event is defined in the name of the ABC. Events. Bus. Entities and is automatically triggered by the Abp when an object is inserted, updated, or deleted. If you have a Person entity, you can register EntityCreatedEventData <Person>. After a new Person is created and inserted into the database, you will be notified. These events also support inheritance. If you have a Student class that inherits from Person and registered EntityCreatedEventData <Person>, you will receive a notification when a Person or Student is inserted.
Trigger event
It is easy to trigger an event:
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}); }}
The Trigger method has several reloads:
EventBus.Trigger<TaskCompletedEventData>(new TaskCompletedEventData { TaskId = 42 }); //Explicitly declare generic argumentEventBus.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)
Another way to trigger an event is to use the DomainEvents set of the AggregateRoot class (view the relevant sections of the object document ).
Event handling
To handle an event, you should implement the IEventHandler <T> interface, as shown below:
public class ActivityWriter : IEventHandler<TaskCompletedEventData>, ITransientDependency{ public void HandleEvent(TaskCompletedEventData eventData) { WriteActivity("A task is completed by id = " + eventData.TaskId); }}
IEventHandler defines the HandleEvent method and implements it as above.
EventBus is integrated into the dependency injection system to implement ITransientDependency as above. When a TaskCompleted event occurs, it creates a new ActivityWriter instance and calls its HandleEvent method, release it and view the dependency injection for more information.
Process basic events
EventBus supports event inheritance. For example, you can create a TaskEventData and two subclasses: TaskCompletedEventData and 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; }}
Then you can implement IEventhandler <TaskEventData> to handle these two events:
public class ActivityWriter : IEventHandler<TaskEventData>, ITransientDependency{ public void HandleEvent(TaskEventData eventData) { if (eventData is TaskCreatedEventData) { //... } else if (eventData is TaskCompletedEventData) { //... } }}
This means that you can implement IEventHandler <EventData> to process all events in the application. You may not want to do this, but it does.
Handler exception
When the Handler throws one or more exceptions, Eventbus triggers all Handler events. If only one Handler throws an exception, the exception is directly thrown by the Trigger method, if multiple handlers throw an exception, EventBus throws only one aggresponexception for them.
Process multiple events
You can process multiple events in a processing program. This time, you should implement IEventHandler for each event, for example:
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... }}
Handler Registration
To handle events, we must register the handler in the event bus.
Automatic
If you find all the classes that implement IEVentHandler and register them with dependency injection (for example, by implementing ITransientDependency, as shown in the preceding example), you can automatically register these classes with the event bus. when an event occurs, ABC uses dependency injection to get the reference of the processing program and release the reference after the event is processed. This is the recommended way to use the event bus in the ABP.
Manual
You can manually register events, but be careful when using them. In a web application, event registration should be completed in application startup. In a Web request, the registration event is not a good method, because after the registration class is completed, continue to register and re-register for each request, which may cause problems, because the registration class is called multiple times. Remember that manual registration does not use dependency injection systems.
The Register Method of the event bus has several reloads. The simplest is to accept a delegate (or lambda ):
EventBus.Register<TaskCompletedEventData>(eventData => { WriteActivity("A task is completed by id = " + eventData.TaskId); });
After the "task completed" event occurs, the lambda method will be called. The second is to accept an object that implements IEventHantler <T>:
EventBus.Register<TaskCompletedEventData>(new ActivityWriter());
Similarly, ActivityWriter instances are called for events. The third overload accepts two generic parameters:
EventBus.Register<TaskCompletedEventData, ActivityWriter>();
This time, the event bus creates a new ActivityWriter for each event. If it is disposable (releasable), it calls the ActivityWriter. Dispose method.
Finally, you can register an event handler to create the handler. A processing factory has two methods: GetHandler and ReleaseHandler. For 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 IocHandlerFactory. It uses the dependency injection system to create/release the handler. This class is also used in automatic registration. Therefore, if you want to use the dependency injection system, you can directly use the previously defined automatic registration.
Anti-registration
After you Register an event with the event bus, the easiest way to do this is to release the value returned by the Register method. For example:
//Register to an event...var registration = EventBus.Register<TaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId) );//Unregister from eventregistration.Dispose();
Of course, you may need to unregister an object elsewhere or at some other time. You can save the object and release it as needed. All the reloads of the Register Method return a releasable object to the event.
EventBus also provides the Unregister method. Example:
//Create a handlervar handler = new ActivityWriter();//Register to the eventEventBus.Register<TaskCompletedEventData>(handler);//Unregister from eventEventBus.Unregister<TaskCompletedEventData>(handler);
It also provides heavy load for anti-registration delegation and factory. The anti-registration handler object must be the object at registration.
Finally, EventBus provides an UnregisterAll <T> () method, which registers all the handlers of an event. The UnregisterAll () method registers all handlers of all events.