Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FluentValidation implicit child validation using manual validation

Reading the documentation it appears that in .NET Core you can do implicit child properties validation with:

services.AddMvc().AddFluentValidation(fv => {
    fv.ImplicitlyValidateChildProperties = true;
});

Unfortunately I'm not working with MVC directly so I have to call Validate myself (IValidator<T> instances are registered by myself with Scrutor). Is there a similar setting for manually validating nested fields as well as top-level fields (using .NET Core DI)?

like image 920
Shoe Diamente Avatar asked Jan 26 '26 00:01

Shoe Diamente


1 Answers

If you check the FluentValidation source code you will notice that the ImplicitlyValidateChildProperties option uses the Asp.Net mechanism of validating nested properties so it won't work for manual validation.

You can write a helper or extension method that uses reflection and the IValidatorFactory service to do nested validation:

public static async Task<ValidationResult> ValidateImplicitAsync<TReq>(this TReq request, IValidatorFactory factory)
            where TReq: class
{
    var result = new ValidationResult();
    await ValidateRecursively(request, factory, result);
    return result;
}

static async Task ValidateRecursively(
            object obj, 
            IValidatorFactory factory, 
            ValidationResult result)
{
    if(obj == null) { return; }
    Type t = obj.GetType();
    IValidator validator = factory.GetValidator(t);
    if(validator == null) { return; }
    ValidationResult r = await validator.ValidateAsync(new ValidationContext<object>(obj));
    foreach(var error in r.Errors)
    {
        result.Errors.Add(error);
    }
    foreach(var prop in t.GetProperties())
    {
        object childValue = prop.GetValue(obj, null);
        await ValidateRecursively(childValue, factory, result);
    }
}

Then you could call it like this:

public class MyService {
    readonly IValidatorFactory factory;
    
    public MyService(IValidatorFactory factory){
       this.factory = factory;
    }

    public async Task Handle(MyModel model){
       ValidationResult validationResult = await model.ValidateImplicitAsync(factory);
       // ... etc...
    }
}
like image 120
Guilherme Meinlschmiedt Abdo Avatar answered Jan 27 '26 16:01

Guilherme Meinlschmiedt Abdo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!