I have the following command handler interface:
public interface ICommandHandler<TCommand> where TCommand : ICommand
{
void Handle(TCommand command);
}
I am decorating instances of this interface with the following concrete class:
public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
where TCommand : ICommand
{
public ValidationCommandHandlerDecorator(
IValidator<TCommand> validator,
ICommandHandler<TCommand> handler)
{
}
public void Handle(TCommand command) { }
}
BUT.... I don't necessarily want to decorate ALL command handlers and only want to decorate the ICommandHandler<TCommand>
IF an instance exists/is registered of IValidator<TCommand>
for the concrete type of TCommand. Note that the IValidator<TCommand>
instance is injected in the constructor of the decorator class.
For example, if I have a command handler:
public class CreateFooCommandHandler : ICommandHandler<CreateFooCommand>
I only want to decorate if I have the following instance registered:
public class CreateFooCommandValidator : IValidator<CreateFooCommand>
If the CreateFooCommandValidator
does not exist then I don't want to decorate the CreateFooCommandHandler
with the ValidationCommandHandlerDecorator
.
I am using the following when registering with SimpleInjector:
var container = new Container();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IValidator<>), assemblies);
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ValidationCommandHandlerDecorator<>));
Obviously this fails if there is not instance of IValidator<>
present for any given ICommandHandler<>
. For info assemblies
is a collection of assemblies used in for registering generic classes.
What should I use to register the decorator/validators to achieve what I want to do, if at all that is possible? I don't want to switch from using SimpleInjector.
Furthermore, if it is possible, is this recommended or is it a violation of SOLID principles, or even just a code smell?
You could register a conditional decorator by analysing registrations in the container and deciding whether to decorate each instance or not but I don't think it's the best option. The simplest solution is to define and register a fallback NullValidator
for those instances where an actual IValidator
does not exist ...
public class NullValidator<TCommand> : IValidator<TCommand> where TCommand : ICommand
{
public void Validate(TCommand command)
{
}
}
Registered as a Conditional:
var container = new Container();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IValidator<>), assemblies);
container.RegisterConditional(
typeof(IValidator<>),
typeof(NullValidator<>),
c => !c.Handled);
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ValidationCommandHandlerDecorator<>));
container.Verify();
I don't want to switch from using SimpleInjector.
Good man!
Furthermore, if it is possible, is this recommended or is it a violation of SOLID principles, or even just a code smell?
This is exactly the kind of thing RegisterConditional
exists for :-)