The Bus
We’ve been working in the area just outside of our Domain Model in terms of building Command Handlers and coordinating activities on the Domain in these Command Handlers. How do Commands make it to our Command Handlers? What if multiple parties are interested in an Aggregate’s state change Event? How does the Read Model find out about Events that are happening in our Write Model?
The answer is the Bus…
“Typically, the bus is a singleton. It receives requests to execute commands and event notifications. The bus doesn’t actually do any concrete work. It just selects a registered component to process the command or handle the event. The bus holds a list of known business processes triggered by commands and events, or advanced by additional commands.” - Dino Esposito
There are two main components to a Bus:
- Message Router
- Message Pipeline (there may be a more official name than this, but that’s what I’m calling it for now)
In Greg Young’s SimpleCQRS solution, he implemented a FakeBus
that is backed by an in-memory Dictionary<Type, List<Action<Message>>>
for a Message Router:
public class FakeBus : ICommandSender, IEventPublisher {
private readonly Dictionary<Type, List<Action<Message>>> _routes = new Dictionary<Type, List<Action<Message>>>();
...
}
The Message Router simply maps Command/Event types to their respective Command/Event Handlers via a Registration that would be done in our Composition Root, e.g. in the Global.asax.cs
in Greg’s project:
protected void Application_Start() {
// instantiate Bus, other stuff and dependencies (or wire up IoC container)
bus.RegisterHandler<CheckInItemsToInventory>(commands.Handle);
...
}
The public void RegisterHandler<T>(Action<T> handler) where T : Message
method takes an ICommandHandler<TCommand>.Handle(TCommand message) method and stores it in a list of
handlersfor a specific
typeof(T)` message.
public void RegisterHandler<T>(Action<T> handler) where T : Message {
List<Action<Message>> handlers;
if (!_routes.TryGetValue(typeof(T), out handlers)) {
handlers = new List<Action<Message>>();
_routes.Add(typeof(T), handlers);
}
handlers.Add((x => handler((T) x)));
}
So when we call:
protected void Application_Start() {
// instantiate Bus, other stuff and dependencies (or wire up IoC container)
bus.RegisterHandler<StartCreatingRoastScheduleCommand>(
new StartCreatingRoastScheduleCommandHandler(repo).Handle);
...
}
We have told the Bus to send StartCreatingRoastScheduleCommand
to StartCreatingRoastScheduleCommandHandler.Handle
method.
For a pretty neat Message Router library written in F# and compatible with C# and VB.NET, check out Quicken Loans’ MessageRouter.
Also, keep in mind that I plan to talk more about the more production-level Bus solutions out there. They include projects like:
Next up, let’s talk about publishing using Events in our architecture to achieve our goals.
I will be releasing most of this content only to subscribers. Make sure you sign up by clicking the big red button!
Related Posts:
- The Read Model
- An Executable Specification
- Testing an Event Sourced Aggregate Root
- Aggregate Event Persistence
- Event Store
- Command Handlers
- Implementing an Event Sourced Aggregate
- Design Level Continued
- Complexity and Cost
- Design Level EventStorming
- People and Commands
- Hotspots
- Domain Discoveries
- Big Picture EventStorming
- The Domain - First Pop Coffee Company
- More Efficient Domain Modeling with EventStorming
- Where do you find resources for learning DDD, CQRS, Event Sourcing, and EventStorming?
- Has the code devolved into a big ball of mud?… What can you do about it?
- A Better Way to Project Domain Entities into DTOs
- Exposing IQueryable in a CQRS Query Stack
- A Pattern to Decouple your Aggregates from their Clients
- Erlang-style Supervisors in C# with Akka.NET and the Actor Model