Decorators
Now that I have a command dispatcher I have decoupled the issuing of the command from the handling of the command. This means that I can change how and where a command is handled without affecting clients.
This led me to the idea of using decorators to add functionality to the handling of a command, and the implementation of cross-cutting concerns is an obvious starting point.
This led me to the idea of using decorators to add functionality to the handling of a command, and the implementation of cross-cutting concerns is an obvious starting point.
There are various cross-cutting concerns that should be implemented outside of the core handler, and most obvious one to implement is logging.
Logging
The ability to log the execution of a command without any code in the handler itself is really useful. Which is what following class does (the actual Log.... methods just write to the _logger field):
public class LoggingDecorator<T> : ICommandHandler<T> { private readonly ICommandHandler<T> _wrappedHandler; private readonly ILogger<ICommandHandler<T>> _logger; public LoggingDecorator( ICommandHandler<T> wrappedHandler, ILogger<ICommandHandler<T>> logger) { _wrappedHandler = wrappedHandler; _logger = logger; } public async Task<CommandResult> HandleAsync(T command) { LogEntry(command); var result = await _wrappedHandler.HandleAsync(command, cancellationToken); if (!result.IsSuccess) { LogFailure(command, result); } LogExit(command); return result; } }
When the command dispatcher is about to send a command to the appropriate handler, it creates a LoggingDecorator instance to wrap it, so the execution of all commands get logged, along with any errors.
Exception Handling
Another basic cross-cutting concern is exception handling. The command handler (or command handling pipeline) is at the boundary of the domain, so it sometimes makes sense to prevent any exceptions bubbling up to outer layers. So an exception handling decorator can be useful as one of the outer handlers.
public class ExceptionHandlingDecorator<T> : ICommandHandler<T> { private readonly ICommandHandler<T> _wrappedHandler; public ExceptionHandlingDecorator( ICommandHandler<T> wrappedHandler) { _wrappedHandler = wrappedHandler; } public async Task<CommandResult> HandleAsync(T command) { try { return await _wrappedHandler.HandleAsync(command); } catch (Exception exception) { return CommandResult.Error(exception.ToString()); } } }
Any exception that occurs anywhere during the handling of a command is caught and returned as a CommandResult, so clients always get a known type of result.
It's obviously useful to log exceptions as they're caught, so either the LoggingDecorator can be the outermost handler (and will therefore log exceptions as the error contained within the CommandResult object), or the ExceptionHandlingDecorator can take a logger as a dependency to log the exception in the catch block.
It's obviously useful to log exceptions as they're caught, so either the LoggingDecorator can be the outermost handler (and will therefore log exceptions as the error contained within the CommandResult object), or the ExceptionHandlingDecorator can take a logger as a dependency to log the exception in the catch block.
Validation
Validation is something that almost every handler needs to perform on the incoming command. What if this could be extracted out into another decorator so that each core handler can just focus on the actual business logic to be executed?
This isn't as simple as logging, as validation is obviously different for every command. So there's an interface to be implemented for any command requiring validation, and then a decorator that takes an instance of that interface. Like this:
This isn't as simple as logging, as validation is obviously different for every command. So there's an interface to be implemented for any command requiring validation, and then a decorator that takes an instance of that interface. Like this:
public interface ICommandValidator<T> { Task<CommandResult> ValidateAsync(T command); }
public class ValidatingDecorator<T> : ICommandHandler<T> { private readonly ICommandHandler<T> _wrappedHandler; private readonly ICommandValidator<T> _commandValidator; public ValidatingDecorator( ICommandHandler<T> wrappedHandler, ICommandValidator<T> commandValidator) { _wrappedHandler = wrappedHandler; _commandValidator = commandValidator; } public async Task<CommandResult> HandleAsync(T command) { var validationResult = await _commandValidator.ValidateAsync(command); if (!validationResult.IsSuccess) { return validationResult; } return await _wrappedHandler.HandleAsync(command); } }
What's Next?
There are a few more decorators that I've used to good effect, so the next blog post will be about two of them: a pre-processing decorator and a post-processing decorator. Til next time!