具有继承的依赖注入

时间:2017-09-12 06:19:30

标签: c# dependency-injection autofac fluentvalidation mediatr

我正在使用MediatR的管道构建。我添加了一个旨在验证查询和命令的简单行为:

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<Result>
    where TResponse : Result
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators ?? Enumerable.Empty<IValidator<TRequest>>();
    }

    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
    {
      (...)
    }
}

目前,我的大多数查询都继承自PaginatedQuery。

public abstract class PaginatedQuery : IQuery
{
    public int Offset { get; set; } = 0;
    public int Limit { get; set; } = 25;
}

示例:

public class GetCountriesQuery : PaginatedQuery
{
    public GetCountriesQuery(PaginatedInput input)
    {
        Limit = input.Limit;
        Offset = input.Offset;
    }
}

为了确保用户不发送无效的偏移/限制,我构建了以下验证器:

public class PaginatedQueryValidator : AbstractValidator<PaginatedQuery>
{
    public PaginatedQueryValidator()
    {
        RuleFor(p => p.Offset)
            .GreaterThanOrEqualTo(0)
            .WithMessage("Offset must be greater or equal to 0");
        RuleFor(p => p.Limit)
            .GreaterThan(0)
            .WithMessage("Limit must be greater than 0");
    }
}

不幸的是,即使TRequest继承自PaginatedQuery,也不会将此验证器注入我的ValidationBehavior。

  

最后,我需要为当前的TRequest和所有母类(即:PaginatedQuery)注入验证器。

这是可以实现的吗?

注意:要注入验证器,我会扫描实现IValidator的所有类型&lt;&gt; (使用Scrutor)

        services.Scan(x =>
            x.FromAssembliesOf(typeof(Startup))
                .AddClasses(c =>
                    c.AssignableToAny(typeof(IValidator<>)))
                .AsImplementedInterfaces()
        );

编辑:我忘了提及我使用的是AutoFac

1 个答案:

答案 0 :(得分:3)

Autofac 解析ValidationBehavior<GetCountriesQuery, GetCountriesResponse>时,您希望它解析IValidator<GetCountriesQuery>,而只有IValidator<PaginatedQuery>注册且IValidator<PaginatedQuery>不能分配给IValidator<GetCountriesQuery> IValidator<GetCountriesQuery> i = (IValidator<PaginatedQuery>)null;

您可以尝试使用以下C#语句

IValidator<PaginatedQuery>

C#编译器会给你这个错误信息

  

错误CS0266:无法将类型IValidator<GetCountriesQuery>隐式转换为IValidator<Base>。存在显式转换(您是否错过了演员?)

为了使其工作,C#4引入了泛型类型参数的协方差和逆变。它允许将IValidator<Derived>投射到in或相反。有关详细信息,请参阅MSDN上的covariance and contravariance

在您的情况下,您需要使用public interface IValidator<in TRequest> { } 关键字

声明的逆转
ContravariantRegistrationSource

为了使 Autofac 与逆变一起使用,您必须注册builder.RegisterSource(new ContravariantRegistrationSource()); 注册源:

['C:\maps\map3.pdf']