2

I am trying to validate List of input Object in my webApi 2.

but it's not validating. Modelstate always is set to true.

Sample code:

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
} 

public class ClassAValidator : AbstractValidator<A>
{
    public classAValidator()
    {
        RuleSet("ClassA",()=>{
            RuleFor(x => x.Id).NotEmpty().WithMessage("The Idcan't be Empty or Zero");
            RuleFor(x => x.Name).NotEmpty().Length(10).WithMessage("Name Should be Six Char length");
        });
    }
}

Note: The string field we need to be exact 6 characters.

Api:

 [HttpPut]
 public async Task<IHttpActionResult> Put([FromBody] List<A> alist)
 {
     if(!ModelState.IsValid) throw new InvalidDataException(ModelState,"Data Validation Failed for Upload Class A"); 
     // Model State is Always true
 }

Can anyone point what I have missed?

Update: I tried as shown in Should i create a new Type for Collection in FluentValidation?

but still having the same issue.

Solved Update:

Issue is usage of Ruleset caused the validation Not getting Triggered. On removing "RuleSet" it worked even without having definition of List[A] Validator class.

Message from Jeremy Skinner : First problem is your rules are wrapped in a Ruleset, so they'll never be executed. Rulesets are opt-in, and the automatic integration only invokes rules not in a ruleset.

3 Answers 3

8

First of all, ModelState.IsValid is an ASP.NET MVC construct verifying (by default) that model binding was done correctly. Unless you set it up in your MVC config, it has nothing to do with FluentValidation.

You need to make sure the Validators are being called. To validate a List of A and it's elements, you need two validators: one for type A, and one for a List/Collection/IEnumerable of A:

public class ClassAValidator : AbstractValidator<A>
{
    public ClassAValidator()
    {
        RuleFor(x => x.Id).NotEmpty().WithMessage("Id can't be empty");
        RuleFor(x => x.Name).NotEmpty().Length(10).WithMessage("Name should have length 10");
    }
}

public class ClassACollectionValidator : AbstractValidator<IEnumerable<A>>
{
    public ClassACollectionValidator ()
    {
        RuleFor(x =>x).SetCollectionValidator(new ClassAValidator());
    }
}

You can then validate your list as follows

 [HttpPut]
 public async Task<IHttpActionResult> Put([FromBody] List<A> alist)
 {
     if(!ModelState.IsValid) throw new InvalidDataException(ModelState,"Data Validation Failed for Upload Class A"); 

     var validator = new ClassACollectionValidator();
     var result = validator.Validate(alist);
 }

Alternatively, you could combine the two validators as follows:

public class ClassACollectionValidator : AbstractValidator<IEnumerable<A>>
{
    public ClassACollectionValidator ()
    {
        RuleForEach(x => x.Id).NotEmpty().WithMessage("Id can't be empty");
        RuleForEach(x => x.Name).NotEmpty().Length(10).WithMessage("Name should have length 10");
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Issue is usage of Ruleset caused the validation Not getting Triggered. On removing "RuleSet" it worked even without having definition of List[A] Validator class.

Message from Jeremy Skinner : First problem is your rules are wrapped in a Ruleset, so they'll never be executed. Rulesets are opt-in, and the automatic integration only invokes rules not in a ruleset.

Comments

-1

It appears that you need the RuleSet wrapped in a constructor, at least according to this example.

https://www.exceptionnotfound.net/custom-validation-in-asp-net-web-api-with-fluentvalidation/

public class ClassAValidator : AbstractValidator<A>
{
    Public ClassAValidator()
    {
      RuleSet("ClassA",()=>{
      RuleFor(x => x.Id).NotEmpty().WithMessage("The Id can't be Empty or Zero");
      RuleFor(x => x.Name).NotEmpty().Length(10).WithMessage("Name Should be Six Char length");
      });
    }

}

1 Comment

sorry forgot to add constructor.. Yes I have actually

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.