I studied a project with domain support in relation to domain events . I really like the separation of problems that these events have. I ran into a problem with the order of saving a domain object and creating domain events. I would like to create events on domain objects, but I want them to be insatiable.
I created the base ShoppingCartService using this Checkout method:
public void Checkout(IEnumerable<ShoppingCartItem> cart, Customer customer) { var order = new Order(cart, customer); _orderRepositorty.Add(order); _unitOfWork.Commit(); }
In this example, the Order constructor raises the OrderCreated event, which can be handled by some handlers. However, I do not want these events to occur when the object has not yet been saved or when something fails.
To solve this problem, I solved several solutions:
1. Raise events in the service:
Instead of raising an event in a domain object, I could raise events in a service. In this case, the Checkout method raises the OrderCreated event. One of the drawbacks of this approach is that when viewing an Order domain object, it is not clear which events occur using which methods. In addition, the developer must remember to raise an event when an order is created elsewhere. This is not true.
2. Queue domain eventsAnother option is to queue events in the domain and increase them when saving. This can be achieved using the using statement, for example:
using (DomainEvents.QueueEvents<OrderCreated>()) { var order = new Order(cart, customer); _orderRepositorty.Add(order); _unitOfWork.Commit(); }
The QueueEvents<T> method would set boolean to true , and the DomainEvents.Raise<T> method would queue the event rather than execute it directly. The dispose QueueEvent<T> executes queues that ensure that this has already occurred. This seems rather complicated and requires the service to know what event occurs in the domain object. In the example I presented, it only supports one type of event that needs to be raised, however this could be circumvented.
3. Saving in a domain eventI could save the object using a domain event. This seems good, except for the fact that the event handler that continues the object should be executed first, however, I read somewhere that domain events should not rely on a specific execution order. Perhaps this is not so important, and domain events can somehow find out in what order the handlers should be executed. For example: suppose I have an interface that defines a domain event handler, the implementation will look like this:
public class NotifyCustomer : IDomainEventHandler<OrderCreated> { public void Handle(OrderCreated args) {
When I want to cope with the continued use of the event handler, I would create another handler obtained from the same interface:
public class PersistOrder : IDomainEventHandler<OrderCreated> { public void Handle(OrderCreated args) {
Now the behavior of NotifyCustomer depends on maintaining order in the database, so the PersistOrder event PersistOrder must execute first. Is it permissible that these handlers introduce a property, for example, that indicates the order in which they are executed? Binding to the implementation of the DomainEvents.Raise<OrderCreated>() method:
foreach (var handler in Container.ResolveAll<IDomainEventHandler<OrderCreated>>().OrderBy(h => h.Order)) { handler.Handle(args); }
Now my question is: do I have any other options? Am I missing something? And what do you think of the solutions I offer?