使用简单的喷油器with the command pattern described here。大多数命令都有配套类,可以实现流畅验证的AbstractValidator<TCommand>
,这意味着它们也可以实现FV IValidator<TCommand>
。然而,对于每个命令都有一个验证器实现并不总是有意义的。当某些类型没有实现时,这是RegisterDecorator的正确方法吗?
据我所知,除非每个ICommandHandler<TCommand>
都有相应的FV,否则命令装饰器实现不能将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()
一次以上的单元测试,从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>
只装修CommandHandler<TCommand>
实例与FluentValidationCommandDecorator<TCommand>
?
未注册的类型解析,得到它。看起来'NullValidator <>'确实属于与simpleinjector相同的库,但是这允许我将装饰器移出。我的NullValidator只是继承了Fluentvalidation的'AbstractValidator' - 没有构造函数,字段,什么都没有 - 并且从我能告诉的是线程安全的,所以我将它注册为单个。 –
danludwig
2012-04-24 21:20:19
这样做的另一个副作用似乎是有两个'IValidator'实现的命令被装饰了两次 - 一次是真正的实现,一次是NullValidator。这是预期的吗? –
danludwig
2012-04-24 21:27:18
我不知道为什么你应该让'NullValidator'成为一个装饰器。我不确定你在做什么。你能用你当前的代码和配置更新你的问题吗? – Steven 2012-04-25 07:14:54