単純なインジェクタを使用with the command pattern described here。ほとんどのコマンドには、流暢な検証のAbstractValidator<TCommand>
を実装するコンパニオンクラスがあります。つまり、FV IValidator<TCommand>
も実装しています。しかし、すべてのコマンドにバリデーターの実装を持たせるのは必ずしも意味がありません。いくつかの型に実装がない場合、これはRegisterDecoratorの正しい方法ですか?
私が知る限り、コマンドデコレータの実装では、ICommandHandler<TCommand>
に対応するFVがない限り、コンストラクタargとしてIValidator<TCommand>
をコンストラクタargとすることはできません。 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()
以上を実行ユニットテストは、2番目の呼び出しに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に依存していません(または、ドメインがコンポジションルートではないため)。
実装はIValidator<TCommand>
のためにそこに登録されている場合のみ、FluentValidationCommandDecorator<TCommand>
とCommandHandler<TCommand>
インスタンスを飾るためにsimpleinjectorを伝える方法はありますか?
登録されていないタイプの解像度です。 'NullValidator <>'はsimpleinjectorで同じlibに属しているようですが、これでデコレータを移動することができます。私のNullValidatorはFluentValidatorの 'AbstractValidator'を継承しています - コンストラクタ、フィールド、何もありません。スレッドセーフであることから、単一として登録しています。 –
danludwig
もう一つの副作用は、 'IValidator'の実装を持つコマンドは、実際の実装で1回、NullValidatorで2回装飾されているということです。これは期待されていますか? –
danludwig
'NullValidator'をデコレータにする理由はわかりません。あなたが何をしているのか分かりません。現在のコードと設定で質問を更新できますか? – Steven