Handling domain events

Last time I wrote a post about the commands. Events are quite similar to the commands – the main difference between these 2 patterns is that the events are related to the things that have actually happened to our entity e.g. by invoking the command. They’re also a core part of the DDD (Domain Driven Design) and can be easily implemented within our software solution.


 

Let’s define our event interface at first:

Now, we can move further and take a look into the base Entity class:

In case you were wondering why I’m using a dictionary here – thanks to this type of a collection I can avoid adding multiple events of the same type e.g. UserEmailChanged and then invoking them multiple times. Yet, again – it’s totally up to you, so feel free to choose the preferable solution.

So far so good, eventually we can define our event once the user’s email was changed.

Remember that you’d better keep your events very thin. Sure thing, you could pass the whole user object, but think outside of the box – what if you want to scale your application on multiple servers? By passing the minimum amount of the information required to identify the entity (e.g. it’s id and maybe an old value along with the new one) you will be able to push such event by message bus or any other communication protocol and handle easily by some external application, without worrying about (de)serialization issues and huge traffic due to the large objects.

And here’s our user:

As you can see, whenever the user changes the email address, we will store such event.
And here comes to the question, how to handle this event? Well, quite easily, so let’s start with the event handler definition:

And the event dispatcher based on the Autofac IoC container:

Speaking of the Autofac, we have to register our handlers and dispatcher, so that IoC magic will be able to happen:

And that’s pretty much it. What you can do now, is, for example, the following:

My approach to the events is mostly based on the Jimmy Bogard’s post which is an opposite to the static pattern described by the Udi Dahan here.

18 Comments Handling domain events

  1. Pingback: Handling domain events - How to Code .NET

  2. Philipp

    var method = handler.GetType()
    .GetRuntimeMethods()
    .First(x => x.Name.Equals(“HandleAsync”));

    This will not work if a handler implements multiple IEventHandler interfaces. This can be a valid possibility. E.g. Sagas that mutate the state on multiple different events.
    Its better to do it like this: ((dynamic)handler).HandleAsync(@event)
    (because you get the handler using the interface you know that method exists)

    Reply
  3. Pingback: Dew Drop - August 1, 2016 (#2299) - Morning Dew

  4. Raham Rahim

    Excellent article, but wouldn’t make more sense to use a ConcurrentDictionary instead of a plain Dictionary?

    Reply
    1. Piotr Gankiewicz

      Hi Jernej,
      In my scenario, I publish the events after the transaction has been completed – for example within the IUserService -> CreateAsync(); dispatching events is the last thing that happens only after the particular operation (e.g. creating and saving a new user in the database) was successfully completed. I hope that it does answers your question (rolling back the transaction would prevent invoking the event dispatcher).

      Reply
  5. Pingback: "Use your feelings, Obi-Wan, and find Links you will." – Yoda - Magnus Udbjørg

  6. jernej

    Makes sense. But I forgot to mention I’m working with a long living db context (desktop app). So after rolling back I would need to clear the _events collection in every entity that participated in the failed transaction whereas if you are returning events from commands, you are not mutating states of any entities.

    Reply
  7. jernej

    One cool side effect when returning events from commands is that you can have a EventDispatcherCommandHandler that you can wrap arround a TransactionalCommandHandler and let the command handling pipeline automatically dispatch events so you don’t need to dispatch them manually from application services 🙂

    Reply
  8. Pingback: Zbudujemy nowy DOM – Dev on board

  9. Zomat

    You used 2 constructor for User class. One of them is paremeterless and other gets email parameter. Do you want to take precautions to don’t send email while update data?

    Reply

Leave A Comment

Your email address will not be published. Required fields are marked *