我正在使用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
答案 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']