Giving the default implementation of Domain Events:
Interface that represents an domain event:
public interface IDomainEvent { }
Interface that represents a generic domain event handler:
public interface IEventHandler<T> where T : IDomainEvent
Central access point to raise new events:
public static class DomainEvents
{
public static void Raise<T>(T event) where T : IDomainEvent
{
//Factory is a IoC container like Ninject. (Service Location/Bad thing)
var eventHandlers = Factory.GetAll<IEventHandler<T>>();
foreach (var handler in eventHandlers )
{
handler.Handle(event);
}
}
}
Consuming:
public class SaleCanceled : IDomainEvent
{
private readonly Sale sale;
public SaleCanceled(Sale sale)
{
this.sale = sale;
}
public Sale Sale
{
get{ return sale; }
}
}
Service that raises the event:
public class SalesService
{
public void CancelSale(int saleId)
{
// do cancel operation
// creates an instance of SaleCanceled event
// raises the event
DomainEvents.Raise(instanceOfSaleCanceledEvent);
}
}
Is there another approach to use Domain Events without use of Service Location anti-pattern?
Use domain events to explicitly implement side effects of changes within your domain. In other words, and using DDD terminology, use domain events to explicitly implement side effects across multiple aggregates.
I guess in your case you really do not have to. Using dependency injection you could inject a IDomainEventDispatcher
implementation into your service.
The reason why I think a singleton like this has made it into the mainstream it was one of the first implementations to be proposed by some prominent developers and at first it doesn't feel too wrong. The other reason is that events may need to be raised from within the domain:
public class Customer
{
public void Enable()
{
_enabled = true;
DomainEvents.Raise(new CustomerEnabledEvent(_id));
}
}
At some stage I came across this post by Jan Kronquist: http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/
This is the third time I have added that link to my answers since I have to give credit to this for changing my thinking. However, I think I'll stop doing that now. Sorry Jan :)
So the point is that we can change our implementation to the following:
public class Customer
{
public CustomerEnabledEvent Enable()
{
_enabled = true;
return new CustomerEnabledEvent(_id);
}
}
Now our service can be changed to use an injected dispatcher:
public class CustomerService
{
private IDomainEventDispatch _dispatcher;
private ICustomerRepository _customerRepository;
public CustomerService(ICustomerRepository customerRepository, IDomainEventDispatch dispatcher)
{
_customerRepository = customerRepository;
_dispatcher = dispatcher;
}
public void Enable(Guid customerId)
{
_dispatcher.Raise(_customerRepository.Get(customerId).Enable());
}
}
So no singleton is required and you can happily inject the dependency.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With