Let’s have a quick discussion about CQRS. There’s a lot to say to be honest, so let’s try to focus on just one thing today: validating your Commands (who knows, I could start a series after this, we’ll see).
The idea is simple: how can I make sure that the data I am passing to my Command Handler is valid?
Also, what is the definition of “valid” ?
There are several aspect to take in consideration, several “levels” of validation. I could just make sure the Command object is not null and/or the data it contains is not empty. Or I could run the validation against some kind of context and check the application Business Rules.
As you can imagine, having different levels means that we could have different implementations scattered in various places/layers of our architecture. For example I could have the API Controller (or whatever outmost layer you have) check for null and perform some Business Context validation later, before or directly in the Command Handler.
In my last project however, I decided to keep things simple and keep my validation in just one place.
Initially the right spot was the Command Handler itself, but of course this would have violated the SRP.
A quick and immediate solution was to have a separate instance of a IValidator<TCommand> injected in the handler. Easy.
Then I realised that my handlers are more “close to the metal” than expected: in most of the cases they access directly the DAL (passing through some kind of IDbContext) and I didn’t wanted to rewrite the call to the IValidator in case I had to switch the persistence layer.
Luckily enough, there’s a nice pattern that came into rescue: the Decorator! As explained very clearly on the SimpleInjector docs, you can create a ValidationCommandHandlerDecorator class, inject an IValidator<TCommand> and let your IoC do the rest.
Bonus tip: in some cases you may want to skip completely the validation. Maybe you have a very good reason or maybe you’re just lazy. Whatever.
In this case, all you have to do is to write some kind of NullValidator<TCommand> class and instruct your IoC to use it when a specific validator is missing for that Command.