What is CQRS?
Let’s start with what is CQS (Command Query Separation) because CQRS (Command Query Responsibility Separation) are derived from it.
CQS (Command Query Separation)
This approach says that each method should be divided into two types:
- Command -the method performs operations, but does not return anything.
- Query –the method return something but do not perform any operations on them.
In brief, you should not have methods such as “UpdatePriceListAndGetProduct“.
“The question should not change the answer.”
CQRS (Command Query Responsibility Separation)
Greg Young and Udi Dahan suggested why not to introduce this division into entire objects instead of individual methods and so the CQRS pattern was created.
The difference between CQS and CQRS is that in CQS we think about methods and in CQRS we think about objects
So the system should be subdivided into the command and query objects.
I will show you how to easily implement the CQRS pattern.
Command
First thing is that we need to create command marker* interface.
*this approach will give us so much that we can easily find our commend in the system, eg. through the reflection system.
Command – it is an object that represents the intentions. For example – CreateUser.
public interface ICommand { }
We have commend, now we need a class that invoke command and it will be CommandHandler.
Command Handler – is responsible for the initial validation of the commend. Then it performs some operations on Domain Object. The last step is to save changes to the database (write) via repository.
Each command has only one handler. This is a generic version of the handlers implementation so we know what type of command it supports.
public interface ICommandHandler { } public interface ICommandHandler<T> : ICommandHandler where T : ICommand { void Handle(T command); }
To handle commends from system, we need a Command Bus.
CommandBus – in the simplest version – looks for the appropriate Command Handler for the given command and calls the Handle method on it.
public interface ICommandBus { void Send<T>(T Command) where T : ICommand; }
Example implementation of such a bus:
public class CommandsBus : ICommandBus { public void Send<TCommand>(TCommand command) where TCommand : ICommand { var handlers = IoC.Container.Resolve<IEnumerable<ICommandHandler<TCommand>>>().ToList(); if (handlers.Count == 1) { handlers[0].Handle(command); } else if (handlers.Count == 0) { throw new System.Exception($"Command does not have any handler {command.GetType().Name}"); } else { throw new System.Exception($"Too many registred handlers - {handlers.Count} for command {command.GetType().Name}"); } } }
In the first place, I downloads all handlers registered by Autofac* to a given commend. Then I check the assumption that each commend can have only one handler and calls operation.
*code for registering commend handlers using autofac on the github repository.
Now we can create a Command – CreateUserCommand
public class CreateUserCommand : ICommand { public string Name{get;} public string Surname{get;} public CreateUserCommand(string name,string surname) { Name = name; Surname = surname; } }
With command handler – CreateUserCommandHandler:
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand> { public void Handle(CreateUserCommand command) { System.Console.WriteLine($"Create user {command.Name} {command.Surname}"); } }
Now, we have everything what we need. It remains only to check if it works via console applications to see how easy it is now. 🙂
public class Program { static void Main(string[] args) { IoC.Cofigure(); var commandBus = new CommandsBus(); commandBus.Send(new CreateUserCommand("Tom","Jerry")); } }
First configure IoC and then call the Command Bus with the appropriate commend.
After starting the application we get the result:
Now we can simply add new commands to the system and we can easily handle them.
Event
The command concept can be extended with events. Events can serve many purposes (eg. Event Sourcing), including informing the system that something has happened. Implementation is analogous to commend:
public interface IEvent { } public interface IEventHandler { } public interface IEventHandler<TEvent> : IEventHandler where TEvent : IEvent { void Handle(TEvent @event); }
The difference in implementation is on the bus.
public interface IEventsBus { void Publish<T>(T @event) where T : IEvent; } public class EventsBus : IEventsBus { public void Publish<T>(T @event) where T : IEvent { var handlers = IoC.Container.Resolve<IEnumerable<IEventHandler<T>>>().ToList(); handlers.ForEach(h=>h.Handle(@event)); } }
The reason is that events can have many handlers.
Now we can create a event – UserWasCreated.
public class UserWasCreated : IEvent { public string Name{get;} public UserWasCreated(string name) { Name = name; } }
To this event we can assign two event handlers for example UserWasValidetedEventHandler and UserWasCreatedEventHandler. Therefore, we want to inform the system at the UserWasCreatedEvent event that it was properly validated and created correctly.
public class UserWasCreatedEventHandler : IEventHandler<UserWasCreated> { public void Handle(UserWasCreated command) { System.Console.WriteLine($"User was created {command.Name} - event"); } } public class UserWasValidetedEventHandler : IEventHandler<UserWasCreated> { public void Handle(UserWasCreated command) { System.Console.WriteLine($"User was validated {command.Name} - event"); } }
Exaggerated example, but I hope you know what I mean. 😉
Now we can inject event bus to our command handlers.
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand> { private readonly IEventsBus _eventPublisher; public CreateUserCommandHandler(IEventsBus eventPublisher) { _eventPublisher = eventPublisher; } public void Handle(CreateUserCommand command) { System.Console.WriteLine($"Create user {command.Name} {command.Surname} - handler"); _eventPublisher.Publish(new UserWasCreated(command.Name)); } }
And we have result as:
The whole code is on github.
Hi,
I was also digging a little bit in CQRS and have one comment about your EventBus implementation. It is tightly coupled with your DI container. I think I know why you did it this way.
When you pass handlers collection via EventBus constructor as IEnumerable, you won’t be allowed to compile the code because of missing method in EventHandler unless method in IEventHandler interface and its implementation will be :
public void Handle(IEvent @event) { }
My attempt of EventBus implementation is also not perfect because of the reason I’ve mentioned and I don’t see a better solution than this.
I’m very glad that I could help. 🙂