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.