DevIQ
Domain Events Pattern
Domain Events Pattern
What are Domain Events?
Domain events are events that signify a state change in the domain. They serve as a mechanism to communicate between different parts of the domain without tightly coupling them. In addition to decoupling different areas of the domain model, domain events can also be used (in concert with integration events) to communicate with other parts of the application (such as the UI) or even other systems.
Pre-Persistence vs Post-Persistence Events
Before diving into code, it's crucial to understand the difference between pre-persistence and post-persistence domain events.
- Pre-Persistence Events: Triggered before the state change is persisted to the database.
- Post-Persistence Events: Triggered after the state change is saved to the database.
To delve deeper into this topic, check out these two resources:
Pre-persistence events are typically triggered and resolved immediately. Post-persistence events are typically queued up on the triggering entity, and then once the entity has been saved, the events are dispatched. This ensures the events are only handled once the state change has been persisted.
Code Examples
The Mediator pattern is commonly used when working with domain events. Let's go through some code examples to understand how to implement Domain Events using MediatR in a C#/.NET application.
First, install the MediatR NuGet package.
Install-Package MediatR
Defining a Domain Event
Let's define a simple domain event. Unlike commands, events can have 0 to many handlers, and should not return a result. The MediatR INotification
type is most appropriate:
public class NewOrderPlacedEvent : INotification{ public int OrderId { get; }
public NewOrderPlacedEvent(int orderId) { OrderId = orderId; }}
Publishing a Domain Event
Here is how you can publish this event using MediatR:
public class OrderService{ private readonly IMediator _mediator;
public OrderService(IMediator mediator) { _mediator = mediator; }
public async Task PlaceOrderAsync(Order order) { // Logic to place order and save changes
await _mediator.Publish(new NewOrderPlacedEvent(order.Id)); }}
Handling a Domain Event
Finally, let's handle the domain event.
public class SendEmailHandler : INotificationHandler<NewOrderPlacedEvent>{ public Task Handle(NewOrderPlacedEvent notification, CancellationToken cancellationToken) { // Logic to send email about the new order return Task.CompletedTask; }}// NOTE: Additional handlers for the same event may be added
Conclusion
The Domain Events pattern is a powerful tool for decoupling different aspects of your domain logic. Using libraries like MediatR makes the implementation in C#/.NET straightforward and clean. Using Domain Events, additional behavior can be added in response to domain state changes, without having to add complexity to the triggering entity or service.
References
- Martin Fowler - Domain Event
- Pre-Persistence Domain Events
- Post-Persistence Domain Events
- More Domain Events Resources
- Sample dotnet Solution with Domain Event Support