Brownfield CQRS part 4 – Command Dispatcher

Spread the love

In the first two posts I talked about commands and command handlers. Now we need to wire them up to invoke them from your service endpoint.

  • Brownfield CQRS part 1 – Commands
  • Brownfield CQRS part 2 – Command Handlers
  • Brownfield CQRS part 3 – Queries, Parameters and Results
  • Brownfield CQRS part 4 – Command Dispatcher

Command Dispatcher

When a command arrives, you simply look up the corresponding handler from your IoC container and invoke it. This responsibility is delegated to a command dispatcher object:

public interface ICommandDispatcher{    void Dispatch<T>(T command) where T : ICommand;}public class CommandDispatcher : ICommandDispatcher{    private readonly IWindsorContainer container;    public CommandDispatcher(IWindsorContainer container)    {        if (container == null) throw new ArgumentNullException("container");        this.container = container;    }    public void Dispatch<T>(T command) where T : ICommand    {        if (command == null) throw new ArgumentNullException("command");        var handler = container.Resolve<ICommandHandler<T>>();        ErrorIfNoHandlerForCommandFound(handler);        handler.Handle(command);    }    private static void ErrorIfNoHandlerForCommandFound<T>(        ICommandHandler<T> handler) where T : ICommand    {        if (handler == null)            throw new NoHandlerForCommandException(typeof(T));    }}

Then we simply inject the command dispatcher into the WCF service and invoke it whenever a command is received:

[ServiceBehavior]public class BookingService : IBookingService{    private readonly ICommandDispatcher commands;    [OperationContract]    public void BookTable(BookTableCommand command)    {        if (command == null) throw new ArgumentNullException("command");        commands.Dispatch(command);    }}

Many of you will note that this is very similar to Udi Dahan’s Domain Events aggregator — the only major difference is CQRS commands are only ever handled by one handler, where domain events are broadcast to anyone who’s listening.

Scaling out

Note this is a synchronous command dispatcher — commands are handled as soon as they arrive. An asynchronous/high-volume system may simply put them in a queue to be executed later by some other component.

Final thoughts

This really is a very introductory series to refactoring an existing application to move towards CQRS. We haven’t even touched on the main goal of CQRS yet — all we’ve done is put clear command/query contracts between our client and server.

It may not sound like much, but doing so allows us to mask non-CQRS components in our system — an anti-corruption layer of sorts — and allows us to proceed refactoring them internally to use different models and storage for commands and queries.