Using simple injector with the command pattern described here. Most commands have companion classes that implement fluent validation's
AbstractValidator<TCommand>
IValidator<TCommand>
IValidator<TCommand>
ICommandHandler<TCommand>
IValidator<TCommand>
public class FluentValidationCommandDecorator<TCommand>
: IHandleCommands<TCommand>
{
public FluentValidationCommandDecorator(IHandleCommands<TCommand> decorated
, IValidator<TCommand> validator
)
{
_decorated = decorated;
_validator = validator;
}
...
}
...
container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);
container.RegisterDecorator(typeof(IHandleCommands<>),
typeof(FluentValidationCommandDecorator<>),
context =>
{
var validatorType =
typeof (IValidator<>).MakeGenericType(
context.ServiceType.GetGenericArguments());
if (container.GetRegistration(validatorType) == null)
return false;
return true;
});
Container.Verify()
Container.Verify()
InvalidOperationException
The configuration is invalid. Creating the instance for type
IValidator<SomeCommandThatHasNoValidatorImplementation> failed. Object reference
not set to an instance of an object.
Container
public class FluentValidationCommandDecorator<TCommand>
: IHandleCommands<TCommand>
{
private readonly IHandleCommands<TCommand> _decorated;
private readonly Container _container;
public FluentValidationCommandDecorator(Container container
, IHandleCommands<TCommand> decorated
)
{
_container = container;
_decorated = decorated;
}
public void Handle(TCommand command)
{
IValidator<TCommand> validator = null;
if (_container.GetRegistration(typeof(IValidator<TCommand>)) != null)
validator = _container.GetInstance<IValidator<TCommand>>();
if (validator != null) validator.ValidateAndThrow(command);
_decorated.Handle(command);
}
}
...
container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);
container.RegisterDecorator(typeof(IHandleCommands<>),
typeof(FluentValidationCommandDecorator<>));
CommandHandler<TCommand>
FluentValidationCommandDecorator<TCommand>
IValidator<TCommand>
What you need is unregistered type resolution, to map missing types to a default implementation. Or in other words, you need to use the RegisterOpenGeneric
method:
container.RegisterOpenGeneric(typeof(IValidator<>),
typeof(NullValidator<>));
Now you need to define a NullValidator<T>
that implements IValidator<T>
with an empty / default implementation.
When you do this every time a certain (unregistered) IValidator<T>
is requested, a new instance of NullValidator<T>
will be returned. It will not override types that are registered using RegisterManyForOpenGeneric
, since those types are explictly registered.
When the NullValidator<T>
implementation is thread-safe (which will usually be the case with a empty implementation), you can optimize construction by registering them as singleton:
container.RegisterSingleOpenGeneric(typeof(IValidator<>),
typeof(NullValidator<>));
You can read more information in the wiki: Registration of open generic types