Skip to content

Validating Commands with the Decorator Pattern

Validating CommandsThis post is how I have manged to handle validating commands and queries and belongs to a series about different aspects of applying CQRS

Although these examples are demonstrating usage in commands, they are aslo applicable to queries.

Examples are using using MediatR to handle our requests.

If you are unfamiliar with CQRS or MediatR, here are some other relevant posts:

Feature

First let’s take a look at our feature for Changing a Customers Pricing Level.  In this example I’ve organized all aspects of this feature into one file.  This single file contains our NancyFX Module and Route, Command and Command Handler.

using System;
using System.Threading.Tasks;
using MediatR;
using Nancy;
using Nancy.ModelBinding;
namespace ThinControllers.Demo.ChangeCustomerPricingLevel
{
public class Module : NancyModule
{
public Module(IMediator mediator)
{
Put["/demo/changepricinglevel/{MessageId:Guid}", true] = async (parameters, token) =>
{
var cmd = this.Bind<Command>();
var envelop = new Envelope<Command>((Guid)parameters.MessageId, cmd);
await mediator.SendAsync(envelop);
return HttpStatusCode.NoContent;
};
}
}
public class Command : IAsyncRequest
{
public Guid CustomerId { get; }
public PricingLevel PricingLevel { get; }
public Command(Guid customerId, PricingLevel pricingLevel)
{
CustomerId = customerId;
PricingLevel = pricingLevel;
}
}
public class Handler : IAsyncRequestHandler<Envelope<Command>, Unit>
{
private readonly CustomeRepository _repository;
public Handler(CustomeRepository repository)
{
_repository = repository;
}
public async Task<Unit> Handle(Envelope<Command> message)
{
var customer = _repository.Get(message.Body.CustomerId);
try
{
customer.SetOperation(message.MessageId);
}
catch (InvalidOperationException)
{
return Unit.Value;
}
customer.ChangePricingLevel(message.Body.PricingLevel);
await _repository.SaveAsync(customer);
return Unit.Value;
}
}
}
view raw feature.cs hosted with ❤ by GitHub

Validation

One small piece of validation I would like to add, is validating the CustomerId is not an empty Guid.

When deserialization occurs thru the Bind() method, if the CustomerId is not present in the payload, the CustomerId will be an empty Guid (00000000-0000-0000-0000-000000000000).

The simplest approach is to add the validation to our Handler.

public class Handler : IAsyncRequestHandler<Envelope<Command>, Unit>
{
private readonly CustomeRepository _repository;
public Handler(CustomeRepository repository)
{
_repository = repository;
}
public async Task<Unit> Handle(Envelope<Command> message)
{
if (message.Body.CustomerId == Guid.Empty) throw new InvalidOperationException("CustomerId cannot be empty.");
var customer = _repository.Get(message.Body.CustomerId);
try
{
customer.SetOperation(message.MessageId);
}
catch (InvalidOperationException)
{
return Unit.Value;
}
customer.ChangePricingLevel(message.Body.PricingLevel);
await _repository.SaveAsync(customer);
return Unit.Value;
}
}
view raw validation.cs hosted with ❤ by GitHub

This doesn’t look incredibly horrible, however we are violating SRP and as you develop more complex commands, validating them will start to consume your Handler.

Decorator Pattern

In object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.[1] The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.[2]

The decorator pattern is pretty straight forward, and even if you never knew the term, you likely already used it.

Here is our decorator for wrapping the command handler with our new validation handler.

using System.Threading.Tasks;
using MediatR;
namespace ThinControllers.Demo
{
public interface IValidationHandler<in TRequest>
{
void Validate(TRequest request);
}
public class RequestValidationDecorator<TRequest> :
IAsyncRequestHandler<TRequest, Unit> where TRequest : IAsyncRequest
{
private readonly IAsyncRequestHandler<TRequest, Unit> _requestHandler;
private readonly IValidationHandler<TRequest> _validationHandler;
public RequestValidationDecorator(IAsyncRequestHandler<TRequest, Unit> requestHandler, IValidationHandler<TRequest> validationHandler)
{
_requestHandler = requestHandler;
_validationHandler = validationHandler;
}
public async Task<Unit> Handle(TRequest message)
{
_validationHandler.Validate(message);
return await _requestHandler.Handle(message);
}
}
}

Validation Handler

Now we can extract our validation logic out of our command handler and add it to a validation handler which will be invoked prior to the command handler.

public class Validation : IValidationHandler<Envelope<Command>>
{
public void Validate(Envelope<Command> message)
{
if (message.Body.CustomerId == Guid.Empty) throw new InvalidOperationException("CustomerId cannot be empty.");
}
}

Invoking

The one piece of the puzzle that I can’t show exactly in this example will be dependent on what container you use.  When you create a new instance of MediatR you provide a single and multi instance factory in the constructor.  Generally this will be your preferred container.   Check out our container docs to see how you register a decorator.

Comments

I’d love to hear how you handle command or query validation.  Please share in the comments below or on twitter.


Related Posts