The code blocks in this section contain pseudo code for illustration purposes. It is not compatible with any specific library including Composable. |
The code blocks in this section contain pseudo code for illustration purposes. It is not compatible with any specific library including Composable. |
Any method call can, if you squint, be viewed as one object sending a message to another object. However, this ties the sender tightly to the receiver. Loose coupling benefits can be had by making the message passing explicit. By sending messages to a receiver through some intermediary rather than directly. Doing so is called messaging.
Messaging is also known as message passing. |
Here we define some terms as they are used in the context of this document.
An object for the purpose of sending data to a receiver.
The System.Type returned by message.GetType()
.
In principle just a function that takes a message as a parameter.
void Handle(RegisterAccountCommand command);
In practice most message handlers need to have one or more dependencies injected into them. In order to support this handlers are often required to be wrapped inside interfaces. That way instances of implementing classes can be resolved from an IOC container easily.
interface IMessageHandler<RegisterAccountCommand>
{
void Handle(RegisterAccountCommand aMessage);
}
The mechanism by which messages are delivered to handlers.
A component which decouples message senders from message handlers. Instead of client code calling handler methods, clients send and receive messages via the bus. The bus is responsible for routing the messages to the appropriate handler(s) and invoking them.
serviceInstance.RegisterAccount(arguments....
bus.Send(new RegisterAccountCommand(
The benefits of this decoupling may not be obvious at first, but they are profound. |
A message that instructs the handler to perform an action.
class RegisterAccountCommand
{
AccountId AccountId { get; }
Password Password { get; }
Email Email { get; }
}
A message that informs handlers about something that has happened.
interface IAccountRegisteredEvent
{
AccountId AccountId { get; }
Password Password { get; }
Email Email { get; }
}
A message that asks the handler to supply some data.
class RecentlyRegisteredAccountsQuery
{
TimeSpan MaxAge { get; }
}
A message handler for a command. Must ensure that the command is successfully executed or throw an exception.
A message handler for a query. Must ensure that the query is successfully executed or throw an exception.
A message handler for an event.
Same as Event Handler.
The action of registering an Event Handler with a service bus.
An event handler registered on a service bus.
Asking a service bus to deliver a message to its handler.
Delivering an event to all it’s subscribers.
Same as Publishing an event
You always publish/Raise events. Keeping Send separate from Publish in your mind is fundamental to understanding. |
Semantic routing is used throughout the toolkit. It is foundational for the Event Store, Service Bus, Query Model updaters and Generators… |
Messages are delivered to every registered handler with a compatible argument type.
Commands and query message types must have exactly one handler.
The first rule is really just polymorphism. |
Semantic Routing is also known as "Polymorphic routing" or "Polymorphic dispatching". |
interface IA
interface IB : IA
interface IC : IB
class A : IA {}
class B : IB {}
class C : IC {}
void HandleA(IA //Handles IA, IB and IC
void HandleB(IB //Handles IB and IC
void HandleC(IC //Handles only IC
serviceBus.Publish(new A()); //Delivered to HandleA
serviceBus.Publish(new B()); //Delivered to HandleA and HandleB
serviceBus.Publish(new C()); //Delivered to HandleA, HandleB and HandleC
Working with events in terms of interfaces maintains flexibility. Here is a partial list of things it is possible to do without having to change any code in any event listener.
Refactoring event classes
Adding event classes
Adding event interfaces
Changing event inheritance hierarchy
Remember to think about events in terms of interfaces. The event classes are an implementation detail that should only ever be known by the code that publishes the event. |
Do not subscribe to event classes. You will lose the benefits just discussed. |