Search code examples
c#validationfluentvalidation

Multiple FluentValidator Rules for one Class


I have a single class

public class Foo
{
    public string Name { get; set;}
    public string Email { get; set;}
    public int Id { get; set;}
}

And my objective is to have 2 differents rules in a FluentValidators for this class. Because i want to be able to check them in different context (ex: i dont need to use the Email Validator when a bool _canSendEmail is false)

So I started by creating 2 FluentValidators like this

public class MailValidator<T> : AbstractValidator<T>
    where T : Foo
{
    public MailValidator()
    {
        RuleFor(f => f.Email).NotNull();
    }
}

public class NameValidator<T> : AbstractValidator<T>
    where T : Foo
{
    public NameValidator()
    {
        RuleFor(f => f.Name).NotNull();
    }
}

And I inject them in Programm.cs

   builder.Services.AddScoped<IValidator<Foo>, NameValidator>();
   builder.Services.AddScoped<IValidator<Foo>, EmailValidator>();

This Solution worked when i want to access to the Validator like this

   private readonly EmailValidator _eamilValidator;

But caused some Dependencies injection error on another project that i couldn't fix because it's accessing to it using this: private readonly IValidator<Foo> _validator;

So my question is: Is there a way to declare a Validator with multiple configuration or function?

In my idea something like this:

public class FooValidator<T> : AbstractValidator<T>
    where T : Foo
{
    public FooValidator()
    {
        ValidateName() // Default call so the other project can acces the validator he needs
    }

    public ValidateMail()
    {
        RuleFor(f => f.Email).NotNull();
    }

    public ValidateName()
    {
        RuleFor(f => f.Name).NotNull();
    }
}

Solution

  • A solution that i found is to declare both of the validator like before and to add them like this

    builder.Services.AddScoped<IValidator<Foo>, NameValidator>();
    builder.Services.AddScoped<IValidator<Foo>, EmailValidator>();
    

    Then, whenever I want to Use à single validator I can do this:

    [Inject] public IEnumerable<IValidator<Foo>> Validators { get; set; }
    
    

    And Select the good one by doing a simple Validators.First(val => val is EmailValidator)

    It's the only way that i found and it made me change a lot of things so any suggestion are welcome