3

我正在使用带有 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<> 的类型(使用 Scrutor)

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

编辑:我忘了提到我正在使用 AutoFac

4

1 回答 1

4

Autofac解析 aValidationBehavior<GetCountriesQuery, GetCountriesResponse>时,您希望它解析 aIValidator<GetCountriesQuery>而只有 aIValidator<PaginatedQuery>已注册并且IValidator<PaginatedQuery>不可分配给IValidator<GetCountriesQuery>

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

IValidator<GetCountriesQuery> i = (IValidator<PaginatedQuery>)null;

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

错误 CS0266:无法将类型隐式转换IValidator<PaginatedQuery>IValidator<GetCountriesQuery>. 存在显式转换(您是否缺少演员表?)

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

在您的情况下,您需要可以使用in关键字声明的逆变

public interface IValidator<in TRequest> { }

为了使Autofac与逆变器一起工作,您必须注册一个ContravariantRegistrationSource注册源:

builder.RegisterSource(new ContravariantRegistrationSource());
于 2017-09-12T19:50:23.623 回答