FluentValidation:如何注入所有已注册的验证器?

3

我正在为一个.Net Core项目使用版本为“10.3.3”的FluentValidation.AspNetCore库。

要注册验证器,我使用以下代码:

services.AddValidatorsFromAssemblyContaining<TestValidator>();

例如,我有一个名为Test的类,我可以像这样注入该类的验证器:

    public class Service : IService
    {
        private readonly IValidator<Test> _testValidator;

        public Service(IValidator<Test> testValidator)
        {
            _testValidator = testValidator;
        }
   }

但我不知道如何将所有已注册的验证器注入到我的服务构造函数中,使其成为IEnumerable实例。那么正确的方法是什么?


如果你真的需要它们全部,那么这个服务做得太多了...但无论如何:你可能可以通过工厂来解决这个问题。 - Fildor
你尝试过注入 IEnumerable<IValidator<Test>> 吗? - Steven
@Steven 是的。使用这种方式,我只能获得继承IValidator<Test>的验证器实例,但程序集中包含其他针对不同实例的验证器。 - Repulse3
@Fildor 我使用服务作为装饰器来验证请求和响应。我有一个包含属于服务的模型验证器的程序集。这就是为什么我想获取它们所有的原因。如果没有其他机会,也许工厂是一种方法。 - Repulse3
所以你想注入一个 IEnumerable<IValidator<object>> 并且让这个列表包含所有已注册的验证器。由于 .NET 类型系统的“限制”,这是不可能的。这与 variance and contra-variance 的工作方式有关。你可以尝试注入某种中介实现,它可以从 IServiceProvider 中动态解析所需的验证器,而不是注入所有验证器。 - Steven
显示剩余2条评论
1个回答

1
FluentValidation中的AddValidatorsFromAssemblyContaining方法会注册所有实现IValidator泛型接口的验证器(link1),并将它们作为泛型接口和自身注册(link2),因此您只能通过具体类型或已构建的泛型(例如IValidator)来解析它们,而无法将它们全部解析为单个集合。
如果您真的想要这样做,可以尝试利用IValidator继承了IValidator的特性,并使用以下有些“hacky”的解决方案:
services.AddValidatorsFromAssemblyContaining(typeof(Val1));

// Only after all validators registrations
var serviceDescriptors = services
    .Where(descriptor => typeof(IValidator) != descriptor.ServiceType
           && typeof(IValidator).IsAssignableFrom(descriptor.ServiceType)
           && descriptor.ServiceType.IsInterface)
    .ToList();

foreach (var descriptor in serviceDescriptors)
{
    services.Add(new ServiceDescriptor(
        typeof(IValidator),
        p => p.GetRequiredService(descriptor.ServiceType),
        descriptor.Lifetime));
}

之后,您将能够解决`IEnumerable `。虽然不确定这对您有多大帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接