ここで説明するコマンドパターンで単純なインジェクターを使用します。ほとんどのコマンドには、流暢な検証を実装するコンパニオンクラスがあります。AbstractValidator<TCommand>
つまり、FVも実装しIValidator<TCommand>
ます。ただし、すべてのコマンドにバリデーターを実装することが常に意味があるとは限りません。
私が知る限り、コマンドデコレータの実装は、すべてに対応するFVが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;
});
1回実行される単体テストContainer.Verify()
に合格します。Container.Verify()
複数回実行される単体テストInvalidOperationException
は、2回目の呼び出しで失敗します。
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<>));
このクラスがSimpleInjectorに依存する必要がない場合は、ドメインプロジェクトに移動できます。ドメインはすでにFluentValidation.netに依存しているため、ドメインの有効性を単体テストできます。このデコレータはドメインに属していると思いますが、このデコレータもその単体テストプロジェクトも、simpleinjectorに依存していません(ドメインはコンポジションルートではないため、依存している必要があります)。
実装が登録されてCommandHandler<TCommand>
いる場合にのみインスタンスを装飾するようにsimpleinjectorに指示する方法はありますか?FluentValidationCommandDecorator<TCommand>
IValidator<TCommand>