Back to List

CQS, SimpleInjector, and the Power of Decorators

Dan Lorenz Dan Lorenz  |  
Jan 08, 2019
 

Over the years of developing with n-tier style, I was wondering if there was anything else out there. The biggest problem with n-tier for me is that the interfaces and classes tend to get super large. When that happens, you start breaking SOLID principals and unit testing becomes much more difficult. Thus, I started to look around at some other techniques that would make classes compact/narrow/follow SOLID, be easy to read/maintain, and make unit tests much easier to write/maintain. I then stumbled upon something called CQS.
 

CQS

CQS stands for Command/Query Separation. In its simplest definition, this just means all your queries (Get/Read) are defined/stored separately from all your commands (Create, Update, Delete). The queries are specialized to return the exact data you need to return, while the commands can take some sort of input and persist with whatever underlying structure you want (like DDD or straight entities in EF).
 

Query

A query simply means when you run the code, the answer doesn’t change. If you call a query over and over, you should get the same answer each time, assuming the data being read behind it stays the same. 
 

Command

A command means you will be changing the state every time you run the code. It also cannot return any data from the command that just finished.
 

CommandQuery

However, like most things in life, there are gray areas. In some cases, such as queues/stacks, you must change the state in order to read the value. In other cases, like auto-incrementing ids, the id isn’t assigned until the create happens, so it becomes troublesome if you need that primary key back to redirect the user to a detail page, for example.

Many people try to solve this problem in different ways. Some people try to go out of their way to keep pure CQS with events, Guids in another column used to read the data out later, or other more complicated ways. Instead, I decided to embrace those one-off situations by creating “CommandQueries”. They are essentially commands that return data that you can’t go forward without. By pushing these to CommandQueries, we now have all areas covered so every type of situation that can occur will be covered.
 

CQRS

There is something else like CQS called CQRS – Command Query Responsibility Separation. While they are similar, they are not the same. The biggest difference is that the read and write models tend be stored in different places, and the writes will eventually update the read model (Datawarehouse essentially). I won’t be talking about that…this time!
 

CQS Interfaces

When implementing CQS, most examples out there end up defining a few generic interfaces to implement the style and get the plumbing hooked up. These include IQuery, IQueryHandler, ICommand, and ICommandHandler. In my version, I force async/await through the chain and force an IResult type back in order to avoid throwing exceptions everywhere. You will tend to see these interfaces defined something like this:
 

    public interface IQuery<TResult>

{   

}   

    public interface IQueryHandler<in TQuery, TResult> where TQuery: IQuery<TResult>

{   

        Task<IResult<TResult>> ExecuteAsync(TQuery query, CancellationToken token = default);

}   

 

In this case, the TQuery is the request (filter) from the client/user, and the TResult is what will be returned when completed. IResult<TResult> will have a Data property returned with its generic type.
 

    public interface ICommand

    {

    }

    public interface ICommandHandler<in TCommand> where TCommand : ICommand

    {

        Task<IResult> ExecuteAsync(TCommand command, CancellationToken token = default);

    }

 

For commands, you just have the TCommand – which is the data being used to change the state. The IResult being returned describes if it was successful or what went wrong, so returning this does not break CQS.  If you were to skip IResult and throw exceptions instead, you could just return Task.

If you also want to go the ICommandQuery route, those would look something like this:
 

    public interface ICommandQuery<TResult>

    {

    }

    public interface ICommandQueryHandler<in TCommandQuery, TResult> where TCommandQuery : ICommandQuery<TResult>

    {

        Task<IResult<TResult>> ExecuteAsync(TCommandQuery commandQuery,

            CancellationToken token = default);

    }

 

This essentially combines both Command and Query styles into one spot. Using a CommandQuery should always be a last resort in order to keep CQS as pure as possible, meaning you must use the data that is created as a result of the command running.

 

Usefulness

So, what exactly can we accomplish with these interfaces and why does this help anything? Let’s take a website, for example. When a user goes to a website, they will perform a lot of GETs/Queries and a few Writes/Commands. Each point of interaction with a user can become its own query/command that is coded with a specific goal in mind. You end up always interacting with a controller if you use ASP.NET MVC. Each method on your controller is either going to be a Query, Command, or CommandQuery and can be mapped 1:1 with a corresponding handler. Each method will either take in an ICommand, IQuery, or ICommandQuery based input (or create one inside the method) that will then be used to call the correct handler.

However, this means that all these handlers for these queries/commands end up being their own class. Each method on a controller will end up calling an individual class that stores the code. You end up with an explosion of classes. Some people will feel this is a bad thing, but the pros far outweigh the cons. The easiest thing to do to mitigate this is to have a well-defined folder structure in place so you can easily find your classes (features) and know where to add them. Since each class is used to complete the single task, you know all the dependencies of the class are needed to complete the request. This pretty much forces you to follow SOLID, which also results in a unit test being very specific to what you are working on and much easier to write. Finally, many developers can be working on them all at once and not have to worry about merge conflicts. However, the real power of this setup will be shown later when we talk about Decorators.
 

Mediators

Before we jump into some simple code examples, there is one other small part to this. Since each query/command is 1:1 with its handler, we can rely on something called a mediator to automatically dispatch that request to the correct handler. The long handler interface names become tedious to define with IoC injection at the controller level, so we can use a mediator instead. A mediator will take the Query/Command/CommandQuery and look up the corresponding handler type for us and call it. This makes the controller code itself not only small but look the same between them. We can add our own custom logic in a mediator to do any global pre- or post-processing if you need to because all the controllers end up calling this same shared class.

In order to pull this off, however, the mediator must be defined in a way that it can reach into the IoC container to do the lookup. This feels a little bit like the Service Locator anti-pattern. Luckily, there is a very easy way to avoid this. Instead of injecting the container into the Mediator, you instead inject Func<Type, dynamic> into the constructor. When you do this, the IoC Container handles the lookup on behalf of the mediator. If you switch IoC containers, the mediators won’t care. You could even create an elaborate mapper if you so choose. A CQS mediator might look something like this:
 

    public interface ICqsMediator

    {

        Task<IResult> ExecuteAsync(ICommand command, CancellationToken token = default);

 

        Task<IResult<TResult>> ExecuteAsync<TResult>(ICommandQuery<TResult> query, CancellationToken token = default);

 

        Task<IResult<TResult>> ExecuteAsync<TResult>(IQuery<TResult> query, CancellationToken token = default);

    }

    public class CqsMediator : ICqsMediator

    {

        private readonly Func<Type, dynamic> _getInstanceCallback;

 

        public CqsMediator(Func<Type, dynamic> getInstanceCallback)

        {

            _getInstanceCallback = getInstanceCallback;

        }

 

        public Task<IResult> ExecuteAsync(ICommand command, CancellationToken token = default)

        {

            var commandType = command.GetType();

            var type = typeof(ICommandHandler<>).MakeGenericType(commandType);

            var instance = _getInstanceCallback(type);

            if (instance == null)

            {

                throw new TypeLoadException(

                    $"No command handler type found for command type: {commandType.FullName}");

            }

            dynamic specificCommand = Convert.ChangeType(command, commandType);

            return instance.ExecuteAsync(specificCommand, token);

        }

 

        public Task<IResult<TResult>> ExecuteAsync<TResult>(

            ICommandQuery<TResult> commandQuery,

            CancellationToken token = default)

        {

            var commnadQueryType = commandQuery.GetType();

            var type = typeof(ICommandQueryHandler<,>).MakeGenericType(commnadQueryType, typeof(TResult));

            var instance = _getInstanceCallback(type);

            if (instance == null)

            {

                throw new TypeLoadException(

                    $"No command query handler type found for query command type: {commnadQueryType.FullName}");

            }

            dynamic specificCommandQuery = Convert.ChangeType(commandQuery, commnadQueryType);

            return instance.ExecuteAsync(specificCommandQuery, token);

        }

 

        public Task<IResult<TResult>> ExecuteAsync<TResult>(

            IQuery<TResult> query,

            CancellationToken token = default)

        {

            var queryType = query.GetType();

            var type = typeof(IQueryHandler<,>).MakeGenericType(queryType, typeof(TResult));

            var instance = _getInstanceCallback(type);

            if (instance == null)

            {

                throw new TypeLoadException(

                    $"No query handler type found for query type: {queryType.FullName}");

            }

            dynamic specificQuery = Convert.ChangeType(query, queryType);

            return instance.ExecuteAsync(specificQuery, token);

        }

    }

 

In the IoC registration, the code to register this would look like this (with SimpleInjector):

container.RegisterSingleton<ICqsMediator>(() => new CqsMediator(type => container.GetInstance(type)));

 

Examples

Now that we’ve covered the basics, we need to jump into the code to show you some of the power here. First, lets start with the controller. If we utilize a query with a mediator, the controller’s responsibility is to handle the user’s request by defining the call and then forwarding it to the mediator. You could unit test the controller, but it will end up not doing much since everything is one line of code that simply forwards the request to the mediator: (In this case, I have a ResponseMediator class defined that converts any errors on IResult to the proper code, or returns Ok with data or success of the query/command running to simplify the call.)
 

Query/Filter object:

    public class CarListQuery : IQuery<ICollection<CarListDto>>

    {

        public string Make { get; set; }

        public string Model { get; set; }

    }

 
 

Return object type:

    public class CarListDto

    {

        public string Name { get; set; }

        public string Make { get; set; }

        public string Model { get; set; }

        public string Color { get; set; }

    }

 

Controller:

    public class CarController : Controller

    {

        private readonly IResponseMediator _responseMediator;

 

        public CarController(IResponseMediator responseMediator) =>

            _responseMediator = responseMediator;

 

        [Route(ApiConstants.RootApiUrlVersion1 + "Cars ")]

        [HttpGet]

        public async Task<IActionResult> Get(CarListQuery query = null) =>

            await _responseMediator.ExecuteAsync(query).ConfigureAwait(false);

    }

 

Every controller would end up looking like this, and each method would be one line of code. The controller’s important part is the route definition to handle the requests, following SOLID from the top.

For the handler itself, we have a lot of options here. You could simply call the database directly, or you could send it to a repository. You could even forward it to n-tier service layer, if you really wanted to. The internal implementation detail is up to you, but the handler definition is a one method call that would look like this if you did direct DB via EF call:
 

    public class CarListQueryHandler : IQueryHandler<CarListQuery, ICollection<CarListDto>>

    {

        private readonly IMyDbContextFactory _connectionFactory;

 

        public CarListQueryHandler(IMyDbContextFactory connectionFactory) =>

            _connectionFactory = connectionFactory;

 

        public async Task<IResult<ICollection<CarListDto>>> ExecuteAsync(CarListQuery query, CancellationToken token = default)

        {

            using (var ctx = _connectionFactory.Create())

            {

                IQueryable<CarEntity> queryData = ctx.Cars;

           

                if (!string.IsNullOrEmpty(query.Make))

                {

                    queryData = queryData.Where(a => a.Make == query.Make);

                }

                if (!string.IsNullOrEmpty(query.Model))

                {

                    queryData = queryData.Where(a => a.Model == query.Model);

                }

               

                return await queryData.Select(a => new CarListDto()

                {

                    Name = a.Name,

                    Make = a.Make,

                    Model = a.Model

                }).ToListAsync(token);

            }

        }

    }

 

The internals of this handler class are totally up to how you want to handle getting the data. If anything needs to be shared, you an always create shared components to inject into your handlers. Also, while possible, you don’t want to have handlers inject other handlers. Instead, inject the shared logic in both handlers or else you could have a big chain mess. You’ll break SOLID since the underlying handler may change its implementation and you’d never know, minus broken integration tests. Next, I’ll show an example of a Command:
 

Command/Request object:

    public class CreateCarCommand : ICommand

    {

        public string Name { get; set; }

        public string Make { get; set; }

        public string Model { get; set; }

    }

 

Controller:

    public class CarController : Controller

    {

        private readonly IResponseMediator _responseMediator;

 

        public CarController(IResponseMediator responseMediator) =>

            _responseMediator = responseMediator;

 

        [Route(ApiConstants.RootApiUrlVersion1 + "Cars")]

        [HttpPost]

        public async Task<IActionResult> Post(CreateCarCommand command = null) =>

            await _responseMediator.ExecuteAsync(command).ConfigureAwait(false);

    }

 

Handler:

public class CreateCarCommandHandler : ICommandHandler<CreateCarCommand>

    {

        private readonly IMyDbContextFactory _connectionFactory;

 

        public CreateCarCommandHandler(IMyDbContextFactory connectionFactory) =>

            _connectionFactory = connectionFactory;

 

        public async Task<IResult> ExecuteAsync(CreateCarCommand command, CancellationToken token = default)

        {

            using (var ctx = _connectionFactory.Create())

            {

                var entity = new CarEntity

                {

                    Name = command.Name,

                    Make = command.Make,

                    Model = command.Model

                };

                ctx.Cars.Add(entity);

                await ctx.SaveChangesAsync().ConfigureAwait(false);

            }

        }

    }

 

Again, you could use your favorite mapper here, create a new aggregate root, forward to a repository, or write your SQL by hand here. It is totally up to you.

 

SimpleInjector

At this point, I hope you are starting to see the power of this style. If not, I still have a few more things to show! Before I can finally talk about Decorators, I need to discuss IoC a little bit. I hope most of you know what IoC is, but I’ll define it briefly here. IoC stands for Inversion of Control. At a very basic level, this means that you are not calling “new” in your classes directly. Instead, your class takes in the dependencies (normally interfaces) it needs via the constructor. An IoC container is defined at the very top of the application. Whenever a new class is needed, the system will ask this container to create the instance for us. When we define the container, we define how to new up each class or let it figure out the dependencies itself from the constructor. The main use of this is so that we code to interfaces, which allows us to do true unit testing since we can mock the implementation.

SimpleInjector is one among many other IoC containers out there. However, what drew me in was the easy way we can register all our CQS interfaces (and Decorators). We can define in one line all queries that exist now and will ever exist in the future and never have to change the registration call:
 

container.Register(typeof(IQueryHandler<,>), assemblies, Lifestyle.Scoped);

container.Register(typeof(ICommandHandler<>), assemblies, Lifestyle.Scoped);

container.Register(typeof(ICommandQueryHandler<,>), assemblies, Lifestyle.Scoped);

 

Since all our handlers follow the same interface, we can register them all right here and SimpleInjector will automatically pick them all up. This removes the worry part of IoC setup since adding new handlers won’t result in making you register new items in the IoC container.

 

Decorators

Finally, we get to discuss decorators. The simplest definition of a decorator is something that wraps a class and adds functionality without changing the target class. In the case of CQS, we can create additional functionality by having a decorator’s constructor take in the same interface it is implementing, run its logic, and then call to the next decorator/handler in the chain. We can add cross-cutting concerns in a single class that affects all handlers that exist now or in the future. We can add things like exception handling, logging, retry, caching, timings, permissions, validation, cache invalidation and more in a single class that can be unit tested and allow the handlers to fully follow SOLID. 

The examples above, if you didn’t notice, don’t mention exception handling anywhere. This is because we can use an exception handling decorator to handle any unhandled exceptions and do whatever we want with it. Here is an example of what a Command Handler Exception Decorator would look like:
 

    public class CommandHandlerExceptionDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : ICommand

    {

        private readonly ICommandHandler<TCommand> _nextCommandHandler;

        private readonly ILogger _logger;

        private readonly IUserContext _userContext;

        private readonly ICommonResource _resource;

 

        public CommandHandlerExceptionDecorator(ICommandHandler<TCommand> nextCommandHandler, ILogger logger, IUserContext userContext, ICommonResource resource)

        {

            _nextCommandHandler = nextCommandHandler;

            _logger = logger;

            _userContext = userContext;

            _resource = resource;

        }

 

        public async Task<IResult> ExecuteAsync(TCommand command, CancellationToken token = default)

        {

            try

            {

                return await _nextCommandHandler.ExecuteAsync(command, token).ConfigureAwait(false);

            }

            catch (BrokenRuleException ex)

            {

                await _logger.LogAsync(new LogEntry(LogTypeEnum.Information, _userContext,

                        "Broken Rule exception with command: " + typeof(TCommand).FullName, ex,

                        new {ex.BrokenRules, command}), token)

                    .ConfigureAwait(false);

                return ResultHelper.ValidationError(ex.BrokenRules);

            }

            catch (UserFriendlyException ex)

            {

                await _logger.LogAsync(new LogEntry(LogTypeEnum.Warning, _userContext,

                        "Friendly exception with command: " + typeof(TCommand).FullName, ex, command), token)

                    .ConfigureAwait(false);

                return ResultHelper.Error(ex.Message);

            }

            catch (DataNotFoundException ex)

            {

                await _logger.LogAsync(new LogEntry(LogTypeEnum.Warning, _userContext,

                        "Data Not Found exception with command: " + typeof(TCommand).FullName, ex, command), token)

                    .ConfigureAwait(false);

                return ResultHelper.NoDataFoundError();

            }

            catch (ConcurrencyException ex)

            {

                await _logger.LogAsync(new LogEntry(LogTypeEnum.Warning, _userContext,

                        "Concurrency exception with command: " + typeof(TCommand).FullName, ex, command), token)

                    .ConfigureAwait(false);

                return ResultHelper.ConcurrencyError();

            }

            catch (NoPermissionException ex)

            {

                await _logger.LogAsync(new LogEntry(LogTypeEnum.Warning, _userContext,

                        "No Permissions exception with command: " + typeof(TCommand).FullName, ex, command), token)

                    .ConfigureAwait(false);

                return ResultHelper.NoPermissionError();

            }

            catch (Exception ex)

            {

                await _logger.LogAsync(new LogEntry(LogTypeEnum.Error, _userContext,

                    "Error with command: " + typeof(TCommand).FullName, ex, command), token).ConfigureAwait(false);

                return ResultHelper.Error(_resource.ErrorGeneric);

            }

        }

    }

 

In this example, we wrap a try/catch around the main call that simply calls the next in the chain, which could be another decorator or the actual handler. If an exception is thrown anywhere in the chain, it will get caught here and logged. We then return the proper type of result depending on the error. Since it is using the same ICommandHandler interface as everything else, all of them will automatically get it. However, you must register these to make that happen – which is where SimpleInjector comes in.

When working with decorators, SimpleInjector makes it incredibly easy to add a new decorator into the chain. In fact, you can register a single decorator for all handlers with one line of code, and it will work for all of them defined now or in the future. The code would look something like this for the exception handler decorator:
 

container.RegisterDecorator(typeof(ICommandHandler<>), typeof(CommandHandlerExceptionDecorator<>));

 

Now any handler that implements ICommandHandler<> will automatically have exception handling built in. You can greatly reduce the clutter in your code and focus on what is important.

One thing to note is that the last defined decorator will be the first one in the chain, so order matters. Last in is run first, going backwards up the chain. 

Finally, there is one more other small trick depending on how you want to work with CQS, SimpleInjector, and handlers. In the decorators themselves, you can also register one that takes in a generic type of its own that is tied to the same command. For example, let’s say that whenever the CarCreateCommand is run, you want to be sure a set of validation rules are run before the handler gets it. That way, you know the request is good if it made it to the handler. You can create a Command Handler Validation Decorator and have it take a list of ICommandValidator<TCommand> types where SimpleInjector will automatically map any classes of the concrete type and inject them automatically.  Here is an example of this:
 

public class CommandHandlerValidatorDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : ICommand

    {

        private readonly ICommandHandler<TCommand> _commandHandler;

        private readonly IValidator _validate;

        private readonly IEnumerable<ICommandValidator<TCommand>> _validators;

 

        public CommandHandlerValidatorDecorator(

            ICommandHandler<TCommand> nextCommandHandler,

            IValidator validate,

            ICollection<ICommandValidator<TCommand>> validators)

        {

            _nextCommandHandler = nextCommandHandler;

            _validate = validate;

            _validators = validators;

        }

 

        public async Task<IResult> ExecuteAsync(TCommand command, CancellationToken token = default)

        {

            var brokenRules = (await Task.WhenAll(_validators.AsParallel()

                    .Select(a => a.ValidateCommandAsync(command, _validate, token)))

                .ConfigureAwait(false)).SelectMany(a => a).Where(a => a != null).ToList();

 

            if (brokenRules.Any())

            {

                return ResultHelper.ValidationError(brokenRules);

            }

 

            return await _nextCommandHandler.ExecuteAsync(command, token).ConfigureAwait(false);

        }

    }

 

Then you could store the validation rules in a separate class from the CreateCommandHandler so each one is focused on one thing and one thing only. Of course, if you follow DDD, you might have validation somewhere else, but this could be used for validating the command itself if you wanted to. Here is an example of what that class would look like (with a small validator framework in the base):
 

    public class CreateCardCommandValidator : CommandValidatorBase<CreateCarCommand>, ICommandValidator<CreateCarCommand>

    {

        private readonly IMyDbContextFactory _contextFactory;

        private readonly IMyResources _resources;

 

        public CreateCardCommandValidator(IMyDbContextFactory contextFactory,

            IMyResources resources)

        {

            _contextFactory = contextFactory;

            _resources = resources;

        }

 

        protected override void CreateRules(CreateCarCommand command, CancellationToken token = default)

        {

            AddRules(

                () => Validate.If(string.IsNullOrEmpty(command.Name))?.BrokenRule(nameof(command.Name))

                    .Required(_resources.CreateCarCommandName),

                () => Validate.If(string.IsNullOrEmpty(command.Make))?.BrokenRule(nameof(command.Make))

                    .Required(_resources.CreateCarCommandMake),

                () => Validate.If(string.IsNullOrEmpty(command.Model))?.BrokenRule(nameof(command.Model))

                    .Required(_resources.CreateCarCommandModel));

        }

    }

 

Then you need to register all generic ICommandValidators in SimpleInjector like this:
 

container.Collection.Register(typeof(ICommandValidator<>), assemblies);

 

Now all command validators that use the same interface will automatically be called by the system no matter what. You won’t have to register new ones you create in the future since they were registered generically by SimpleInjector. This is what makes CQS, SimpleInjector, and Decorators a powerful combination that should reduce code complexity, force SOLID principals, make unit tests easier, and allow you to focus on the code that really matters.

I’d love to hear any of your thoughts or questions on this in the future!

 

Love our Blogs?

Sign up to get notified of new Skyline posts.

 


Related Content


Spring 2019 Kentico User Group
Apr 17, 2019
Location: Waukesha County Technical College - Pewaukee Campus - 800 Main Street, Pewaukee, Wisconsin 53072 - Building: Q, Room: Q361
Blog Article
Azure Tips & Tricks: Application Insights Snapshot Debugger
Todd TaylorTodd Taylor  |  
May 21, 2019
A painful memory that is burned into my developer-brain is a production support issue for a .NET web API that I wrote years ago. I worked for a large retailer at the time, and the bug was preventing electronic pricing signs from displaying the most up-to-date price for hundreds of products at...
Blog Article
Thinking Outside the Application Development Box with Unity
Jeff WeberJeff Weber  |  
May 14, 2019
Do you or your company have an idea for an application that sits a little outside your comfort zone? Does your idea possibly require game-like graphics, Augmented Reality, Virtual Reality or similar technology? If so, Unity might be worth a look.   I’ve been using Unity in my spare...
Blog Article
Creating and Installing Project Templates in .NET Core
Ben BuhrBen Buhr  |  
Apr 30, 2019
In my previous blog article, we examined the .NET Core Command Line Interface (CLI). As part of that, we saw that templates in .NET Core can be very useful. Templates in .NET Core are very easy to create, and there already are a ton of very helpful ones available. They allow us to quickly get an...
Blog Article
How to Overcome the 5 Common Barriers to Manufacturing Innovation
Mitch WeckopMitch Weckop  |  
Apr 04, 2019
Manufacturing companies have an opportunity ahead of them – thanks in large part to information technology advances. These advances are increasing the rate of product innovation, improving cost and quality, enabling planned and predictive maintenance, and launching new business platforms...