Container-friendly domain events

A lot of times an operation on a single aggregate root needs to result in side effects that are outside the aggregate root boundary.  There are several ways to accomplish this, such as:

  • A return parameter on the method
  • A collecting parameter
  • Domain events

We’ve used the default implementation of domain events for quite a while, but with some recent applications I’ve worked on, we’ve noticed one small design issue:

    public static class DomainEvents

It’s that big ol’ “static” piece.  Domain events are then raised explicitly by calling this static method, Raise:

public static IHandlerContainer Container { get; set; }

public static void Raise<TEvent>(TEvent args) where TEvent : IDomainEvent
{
    if (Container != null)
        Container.GetAllHandlers<TEvent>()
            .Cast<IHandler<TEvent>>()
            .ForEach(x => x.Handle(args));

Where Container in this case is just a facade over an IoC container.  The silly Cast is from this being C# 3.0 code, the contravariance of C# 4.0 would fix this.  Again, another design issue here.  The reference to the container is static.  This means that more powerful container patterns such as nested containers are out of the picture.  This is too bad, because nested containers are another great tool in the toolbox that lets us delete a lot of code that sets up contexts for things.

The problem here is that I still want to raise events in a static manner from an entity.  I don’t want to have to reference some event pipeline object thingy in my domain objects, and I’m really not keen to start injecting things.  Instead, I want a true, fire-and-forget event.

Contextual containers and disposable actions

What I need to do is allow this static method to work with a contextual, scoped piece of code.  But that’s exactly what the “using” statement allows us to do – create a scoped piece of code, that executes something at the beginning (whatever creates the IDisposable) and something at the end (the Dispose method).

To help us create this scoped context to slip in our nested container, we can take advantage of Ayende’s most brilliant piece of code ever written, the DisposableAction:

public class DisposableAction : IDisposable
{
    private readonly Action _callback;

    public DisposableAction(Action callback)
    {
        _callback = callback;
    }

    public void Dispose()
    {
        _callback();
    }
}

I can then just implement a simple method on the DomainEvents class to allow me to swap out – and then restore – the container reference:

public static IDisposable CreateContext(IHandlerContainer container)
{
    var existingContainer = Container;
    Container = container;

    return new DisposableAction(() =>
    {
        Container = existingContainer;
    });
}

I keep a reference around to the previous container, then swap out the DomainEvents’ container for the one passed in.  When this CreateContext is finished, the DisposableAction restores the previous container with a handy closure.

So how do I use this in real code?  Something like:

public void Process<T>(T message) where T : IMessage
{
    using (var nestedContainer = _container.GetNestedContainer())
    using (var unitOfWork = new UnitOfWork(_sessionSource))
    using (DomainEvents.CreateContext(new HandlerContainer(nestedContainer)))

I have several scoped items I’m using to process a message (part of a batch processing program).  Each line in a file gets processed as a single message, with its own unit of work, its own container etc.  It’s now very plain to see the context I create to process the message because I just use the C# feature that creates bounded, self-cleaning contexts: the “using” statement.

This method still isn’t thread-safe, as it still has static elements.  I’ve just allowed a scoped, nested container to be used instead of a single, global static ontainer.  Some folks mentioned patterns like event aggregators, so there are likely other patterns that can help out with the static nature of this domain events pattern.  But for now, I can harness the power and simplicity of nested containers, and keep my handy domain events around as well.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Domain-Driven Design. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.UdiDahan.com Udi Dahan

    Why would you be processing a batch of messages together to begin with if each one is its own unit of work? You could just send each message in the batch to another endpoint and then the message boundary already gives you all the scoping you need.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Udi

    That’s step 2 in a refactoring towards messaging, this is the midway point. Originally this code had no concept of a message, transactional boundaries or anything. Step 1 – convert a batch process to create a message from each line, but keep the processing synchronous. Step 2 – this message broker would instead just fire off the message.

  • Joe

    I feel really stupid asking, but could you post an end-to-end example of this?  I’m not seeing how your domain model still doesn’t need a reference to your handler container. 

    • http://profiles.google.com/jimmy.bogard Jimmy Bogard

      It’s still a static call to DomainEvents.Raise, that’s all. That part didn’t change from the link in the post above.

      • Joe

        Thanks. I figured it out from your other post on using StructureMap registries to find generic interfaces.  In my app startup, SM finds my listener interfaces, then I add them to the static DomainEvents container of handlers, and the rest is easy.  Thanks for your great posts on the subject! 

  • Joe

    I feel really stupid asking, but could you post an end-to-end example of this?  I’m not seeing how your domain model still doesn’t need a reference to your handler container. 

  • http://www.hollman-alu.nl Aluminium Kozijnen

    I think here we can change that design whatever we want.. Very useful one..