Peter Morlion logo


CQRS/ES In .NET: The CommandHandler

In my previous post, I explained how the Command in (our) CQRS implementation is just a DTO. This means we need to send it somewhere. Meet the CommandHandler.

First, let’s define the interface. This will come in handy when we want to use dependency injection later. In my case, I injected the interface into my ASP.NET controllers so I could easily unit test them.

The interface is simple:

public interface ICommandHandler<in T> where T : ICommand
    void Handle(T command);

There’s not much to it, except for the fact that we only allow implementations where T implements ICommand.

This is an example implementation:

public class ChatCommandHandler : ICommandHandler<AddChatMessage> 
    private readonly IEventSourcedRepository<Chat> _repository;

    public ChatCommandHandler(IEventSourcedRepository<Chat> repository) 
        _repository = repository;

    public void Handle(AddChatMessage command) 
        var chat = _repository.Find(command.ChatId);

        _repository.Save(chat, command.Id.ToString());

There are several things to note here.

First, we’ve implemented the interface. Your command handler could implement multiple interfaces if you want. As you can see, in my case the implementation of the Handle command is just retrieving the correct object, calling the relevant method with the relevant parameters, and saving it.

If there are multiple commands to perform on the Chat object, you could add these implementations to the ChatCommandHandler. For example, it could implement ICommandHandler<RemoveChatMessage>. But if you prefer, you could have each command handler be responsible for only one type of command.

Moving on, we can see we need a repository to retrieve and save an object. Here, it’s an IEventSourcedRepository<Chat>, which we’ll get into in the next post.

And the last thing to note is that the implementation is very simple. As I mentioned above, it does only three things. Almost all my command handlers are this simple. They just function as a mechanism to pass the command from the ASP.NET controller to the aggregate. I recommend avoiding putting logic in this class.

Why not just call the repository and aggregate in our ASP.NET controllers? You could do that I guess, but I wanted to keep my entire CQRS/ES-driven Domain layer in a separate assembly, regardless of technological context it is run in. Currently, I run it in an ASP.NET application, but by keeping the classes basic .NET classes with little connection to a specific technology, I can more easily port it to another platform, like .NET Core.

So far, we’ve covered the Command and the Command Handler. Both were very simple classes with hardly any complex logic. In the Command Handler we saw we needed a repository to retrieve and save our aggregates. This will be a little more complex. Let’s move on to this in our next post.

Leave a Reply

Your email address will not be published. Required fields are marked *