Использование простого инжектора с шаблоном команды, описанным здесь. У большинства команд есть сопутствующие классы, которые реализуют AbstractValidator<TCommand>
плавной проверки, а это значит, что они также реализуют FV IValidator<TCommand>
. Однако не всегда имеет смысл иметь реализацию валидатора для каждой команды.
Насколько я могу судить, реализация декоратора команд не может принимать IValidator<TCommand>
в качестве аргумента конструктора, если у каждого ICommandHandler<TCommand>
нет соответствующего FV.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<>));
Если бы этому классу не нужно было зависеть от Simple Injector, я мог бы переместить его в доменный проект. Домен уже зависит от FluentValidation.net, поэтому допустимость домена можно протестировать. Я думаю, что этот декоратор принадлежит домену, но ни он, ни его проект модульного тестирования не зависят от simpleinjector (или должны были бы, поскольку домен не является корнем композиции).
Есть ли способ указать simpleinjector украшать экземпляр CommandHandler<TCommand>
экземпляром FluentValidationCommandDecorator<TCommand>
только в том случае, если для IValidator<TCommand>
зарегистрирована реализация?