You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不破坏DI注册的情况下向FluentValidation验证器传参?

问题:FluentValidation子验证器带参数时DI注册失败,父验证器通过SetValidator传参

需要通过.SetValidator()方法从父验证器向子验证器传递参数,但子验证器带有参数时,使用FluentValidation的自动注册功能将其注册到DI容器时遇到构造错误。

父验证器代码

public class FooValidator: AbstractValidator<Foo>
{
    public FooValidator()
    {
        RuleFor(foo => foo.Bar)
            .SetValidator(foo => new BarValidator(foo.SomeStringValue))
            .When(foo => foo.Bar != null);
    }
}

子验证器代码

public class BarValidator: AbstractValidator<Bar>
{
    public BarValidator(string someStringValue)
    {
        RuleFor(bar => bar.Baz)
            .Must(BeValid(bar.Baz, someStringValue)
            .When(bar => bar.Baz != null);
    }
    
    private static bool BeValid(Baz baz, string someStringValue)
    {
        return baz == someStringValue; 
    }
}

DI注册代码

services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly(), ServiceLifetime.Transient);

错误信息

System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: FluentValidation.IValidator`1[Domain.ValueObjects.Bar] Lifetime: Transient ImplementationType: Application.Common.Validators.BarValidator': 
    Unable to resolve service for type 'System.String' while attempting to activate 'Application.Common.Validators.BarValidator'.)
---&gt; System.InvalidOperationException: Unable to resolve service for type 'System.String' while attempting to activate 'Application.Common.Validators.BarValidator'.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
   --- End of inner exception stack trace ---
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
   --- End of inner exception stack trace ---
   at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
   at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
   at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()
   at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
   at Program.&lt;Main&gt;$(String[] args) in C:\Program.cs:line 9

环境信息

  • .NET 7
  • FluentValidation v11.2.2
  • Microsoft.Extensions.DependencyInjection

已尝试的无效方法

_ = services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly(), ServiceLifetime.Transient, filter => filter.ValidatorType != typeof(BarValidator));
_ = services.AddTransient<IValidator<Bar>>(_ => new BarValidator(""));

解决方案

1. 修正子验证器的语法错误

子验证器中Must方法的调用存在语法错误,需改为Lambda表达式传递参数:

public class BarValidator: AbstractValidator<Bar>
{
    public BarValidator(string someStringValue)
    {
        RuleFor(bar => bar.Baz)
            .Must(baz => BeValid(baz, someStringValue)) // 修正为Lambda表达式
            .When(bar => bar.Baz != null);
    }
    
    private static bool BeValid(Baz baz, string someStringValue)
    {
        // 增加空判断,避免空引用异常
        return baz?.ToString() == someStringValue; 
    }
}

2. 排除子验证器的自动注册

由于父验证器是手动实例化子验证器,不需要DI容器提供BarValidator的实例,因此需要阻止FluentValidation自动注册它,有两种方式:

方式一:使用过滤条件排除

在自动注册时通过filter排除BarValidator,且不需要手动注册它:

services.AddValidatorsFromAssembly(
    Assembly.GetExecutingAssembly(),
    ServiceLifetime.Transient,
    // 确保这里的类型是正确的BarValidator类型(注意命名空间)
    filter => filter.ValidatorType != typeof(BarValidator)
);

方式二:使用[ValidatorIgnore]特性

给BarValidator添加FluentValidation提供的[ValidatorIgnore]特性,自动注册时会忽略该验证器:

using FluentValidation;

[ValidatorIgnore]
public class BarValidator: AbstractValidator<Bar>
{
    // 代码不变
}

此时DI注册代码可简化为:

services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly(), ServiceLifetime.Transient);

关键说明

错误的核心原因是AddValidatorsFromAssembly会自动扫描并注册所有继承AbstractValidator<T>的类型,但BarValidator的构造函数需要字符串参数,DI容器无法自动解析该参数。而父验证器中是直接手动创建BarValidator实例,完全不需要DI容器介入,因此只需阻止BarValidator被注册到DI即可解决问题。


内容的提问来源于stack exchange,提问作者trymv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 20:45:44