我们目前使用SimpleInjector作为DI容器,通过使用ICommand
和IQuery<TResult>
以及ICommandHandler<TCommand>
和IQueryHandler<TQuery, TResult>
接口来实现命令-查询-分离(CQS)模式。
我们还使用装饰器模式执行面向方面的编程。对于其中一个装饰器,我们使用FluentValidation来为特定的命令或查询执行验证逻辑。
使用SimpleInjector,可以有条件地注册类型。当我们有一个命令或查询没有相应的验证器时,这对我们的FluentValidation装饰器很有用。然后我们使用NullValidator<T>
作为不做任何事情的回退。这个场景在SimpleInjector文档中有详细描述,它看起来像这样:
public class NullValidator<T> : AbstractValidator<T>
{
}
container.RegisterConditional(
typeof(IValidator<>),
typeof(NullValidator<>),
c => !c.Handled); // Applied if no other validator matches
NullValidator<T>
是必需的,因为装饰器总是被应用,IValidator<T>
总是被注入。对于不存在的特定验证器,使用NullValidator<T>
。下面是命令的FluentValidation装饰器的构造函数:
public FluentValidationCommandHandlerDecorator(
IValidator<TCommand> validator,
ICommandHandler<TCommand> decoratee)
{
this.validator = validator ?? throw new ArgumentNullException(nameof(validator));
this.decoratee = decoratee ?? throw new ArgumentNullException(nameof(decoratee));
}
这工作得很好,但现在我们正在评估消除对SimpleInjector的依赖,并使用。net依赖注入(IServiceCollection
从Microsoft.Extensions.DependencyInjection
)与Scrutor结合来注册我们的ICommandHandler<T>
和IQueryHandler<TQuery, TResult>
实现和我们的装饰器。
有没有办法执行类似的条件注册逻辑或回退机制像SimpleInjector支持在。net DI框架?
我设法通过在FluentValidationCommandHandlerDecorator
装饰器中注入IEnumerable<IValidator<T>>
而不是单个IValidator<T>
实例来解决这个问题。在这种情况下,我根本不需要NullValidator<T>
,如果没有验证器可用于特定命令或查询,则注入空集合。
SimpleInjector必须更改为注册IValidator<T>
实例的集合:
container.Collection.Register(typeof(IValidator<>), assemblies);
Microsoft.Extensions.DependencyInjection
DI容器支持开箱即用注入IEnumerable<IValidator<T>>
,而无需更改注册中的任何内容。