Local Event Bus
There are two ways of publishing local events explained in the following sections.
can be injected and used to publish a local event.
Example: Publish a local event when the stock count of a product changes
PublishAsync
method gets a single parameter: the event object, which is responsible to hold the data related to the event. It is a simple plain class:
Even if you don’t need to transfer any data, you need to create a class (which is an empty class in this case).
can not inject services via dependency injection, but it is very common to publish local events inside entity / aggregate root classes.
Example: Publish a local event inside an aggregate root method
AggregateRoot
class defines the AddLocalEvent
to add a new local event, that is published when the aggregate root object is saved (created, updated or deleted) into the database.
IGeneratesDomainEvents Interface
Actually, adding local events are not unique to the AggregateRoot
class. You can implement IGeneratesDomainEvents
for any entity class. But, AggregateRoot
implements it by default and makes it easy for you.
How It Was Implemented?
Calling the AddLocalEvent
doesn’t immediately publish the event. The event is published when you save changes to the database;
- For EF Core, it is published on
DbContext.SaveChanges
. - For MongoDB, it is published when you call repository’s
InsertAsync
, orDeleteAsync
methods (since MongoDB has not a change tracking system).
A service can implement the ILocalEventHandler<TEvent>
to handle the event.
Example: Handle the StockCountChangedEvent
defined above
That’s all. MyHandler
is automatically discovered by the ABP Framework and HandleEventAsync
is called whenever a StockCountChangedEvent
occurs. You can inject any service and perform any required logic here.
- Zero or more handlers can subscribe to the same event.
- A single event handler class can subscribe to multiple events but implementing the
ILocalEventHandler<TEvent>
interface for each event type.
If you perform database operations and use the repositories inside the event handler, you may need to create a , because some repository methods need to work inside an active unit of work. Make the handle method virtual
and add a [UnitOfWork]
attribute for the method, or manually use the IUnitOfWorkManager
to create a unit of work scope.
- If a handler throws an exception, it effects the code that published the event. That means it gets the exception on the call. So, use try-catch yourself in the event handler if you want to hide the error.
- If the event publishing code is being executed inside a Unit Of Work scope, the event handlers also covered by the unit of work. That means if your UOW is transactional and a handler throws an exception, the transaction is rolled back.
It is very common to publish events on entity create, update and delete operations. ABP Framework automatically publish these events for all entities. You can just subscribe to the related event.
Example: Subscribe to an event that published when a user was created
This class subscribes to the EntityCreatedEventData<IdentityUser>
, which is published just after a user was created. You may want to send a “Welcome” email to the new user.
There are two types of these events: events with past tense and events with continuous tense.
Events with past tense are published when the related unit of work completed and the entity change successfully saved to the database. If you throw an exception on these event handlers, it can not rollback the transaction since it was already committed.
The event types are;
EntityUpdatedEventData<T>
is published just after an entity was successfully updated.EntityDeletedEventData<T>
is published just after an entity was successfully deleted.EntityChangedEventData<T>
is published just after an entity was successfully created, updated or deleted. It can be a shortcut if you need to listen any type of change - instead of subscribing to the individual events.
Events with continuous tense are published before completing the transaction (if database transaction is supported by the database provider being used). If you throw an exception on these event handlers, it can rollback the transaction since it is not completed yet and the change is not saved to the database.
The event types are;
EntityCreatingEventData<T>
is published just before saving a new entity to the database.EntityUpdatingEventData<T>
is published just before an existing entity is being updated.EntityDeletingEventData<T>
is published just before an entity is being deleted.EntityChangingEventData<T>
is published just before an entity is being created, updated or deleted. It can be a shortcut if you need to listen any type of change - instead of subscribing to the individual events.
How It Was Implemented?
- For EF Core, they are published on
DbContext.SaveChanges
.