Monday, May 20, 2013

Taking Domain Events Up a Notch

Also take a look at my followup posts:

A few years back, a friend of mine forwarded me a blog post from Udi Dahan about Domain Events.  Since then, I have implemented this at 3 different companies, and probably about 7 projects.

The code below takes Udi's vision and extends it in a few ways:
  • Interfaces with your IoC framework
  • Auto-register all handlers
  • Raises the handlers asynchronously so your calling code can continue immediately
  • Executes the handlers in parallel ala TPL
  • It is all testable using mocks
An event is any class (I highly recommend small POCO's) that implements IEvent:

Handling an event is very easy, and a class can handle multiple events.

An example of this might look like the following:

The code that executes the event is part of the following interface:

If you want to raise an event, simply inject your implementation of IEventer and call the Raise method:

So, now lets look at what the implementation of IEventer looks like:

The Raise<T> method gets all the configured objects from the IoC framework, and calls their Handle method. It does this in a new task so that the caller can immediately continue any work it was doing, or it can utilize the return Task to wait. The handlers are executed in parallel to speed up the execution. If you don't like the parallel execution, just remove it and loop through them one at a time.

In this example, I have coupled my IEventer implementation to Autofac.  I really like this IoC framework, but you can easily substitue your favorite one in its place, or use IDependencyResolver from MVC if you are using this in a website.

Now, lets look at the auto-registration code.  On the application start event,we use some fancy reflection to auto-register all of our event handlers:

Yes, this code can be optimized and cleaned up a bit more, but you get the idea. Again, this is coupled to Autofac, but it would be easy to switch it to the IoC framework of your choice. This code will iterate through all the specified assemblies (you can use AppDomain.CurrentDomain.GetAssemblies()), finds all classes that implement IEventHandles<>, verifies that they are registered, and appends the registration with IEventHandles<>.

Please let me know what you think! In a future blog post, I'll talk about how to raise an event via a MVC controller, view some diagnostics information on the events and handlers, and how to interface with Redis' PubSub system.