4

I'm using Fluent Validation v5.5 with ASP.NET v5.2.2 and I'm getting some inconsistent results with the validation.

My view model is:

public class QuoteViewModel
{
    [Display(Name = @"Day")]
    public int DateOfBirthDay { get; set; }

    [Display(Name = @"Month")]
    public int DateOfBirthMonth { get; set; }

    [Display(Name = @"Year")]
    public int DateOfBirthYear { get; set; }

    [Display(Name = @"Gender")]
    public Gender? Gender { get; set; }

    [Display(Name = @"State")]
    public int StateId { get; set; }
}

My controller method is:

public ActionResult Quote(QuoteViewModel viewModel)
{
    var _validator = new QuoteValidator();
    var results = _validator.Validate(viewModel);

    if (!ModelState.IsValid)
    {
        return Json(false);
    }

    return Json(true);
}

My validator is:

public class QuoteValidator : AbstractValidator<QuoteViewModel>
{
    public QuoteValidator()
    {
        RuleFor(x => x.Gender).NotEmpty();
        RuleFor(x => x.StateId).NotEmpty();
        RuleFor(x => x.DateOfBirthDay).NotEmpty().InclusiveBetween(1, 31);
        RuleFor(x => x.DateOfBirthMonth).NotEmpty().InclusiveBetween(1, 12);
        RuleFor(x => x.DateOfBirthYear).NotEmpty().LessThanOrEqualTo(DateTime.UtcNow.Year);
    }
}

I'm running a test that posts all blank value form fields. Thus the view model fields retain default values after the view model object is created.

For comparison, in the controller I'm running the validation explicitly and the results aren't consistent with the validation result in ModelState.

ModelState is showing 4 errors, all triggered by NotEmpty rules. NotEmpty on the nullable enum Gender doesn't seem to trigger.

The explicit validation is returning 7 out of 8 errors, the LessThanOrEqualTo rule won't fire since the DateOfBirthYear defaults to zero.

My pain point is I can't figure out why ModelState is missing the NotEmpty error on the nullable enum Gender.

The only way I've been able to trigger that error is to post just the Gender value.

Please help.

EDIT:

After stepping through some code, it appears that the issue is related to the Fluent Validation RequiredFluentValidationPropertyValidator. The Gender field is a nullable value type which is bound to null. The following snippet from RequiredFluentValidationPropertyValidator prevents validation:

ShouldValidate = isNonNullableValueType && nullWasSpecified;
1
  • why not simply chech this RuleFor(x => x.Gender).NotNull() ? Commented Jul 12, 2017 at 18:57

1 Answer 1

1

!ModelState.IsValid doesn't use your validation result it uses defaulf MVC validation (that can be added through DataAnnotations). You have to check !results.IsValid instead which contains the validation result of your QuoteValidator.

If you want to use default ModelState.IsValid you have to mark your model with validator attribute:

[Validator(typeof(QuoteValidator))]
public class QuoteViewModel
{
    [Display(Name = @"Day")]
    public int DateOfBirthDay { get; set; }

    [Display(Name = @"Month")]
    public int DateOfBirthMonth { get; set; }

    [Display(Name = @"Year")]
    public int DateOfBirthYear { get; set; }

    [Display(Name = @"Gender")]
    public Gender? Gender { get; set; }

    [Display(Name = @"State")]
    public int StateId { get; set; }
}

And add the following line to your Application_Start method:

protected void Application_Start() {
    FluentValidationModelValidatorProvider.Configure();
}
Sign up to request clarification or add additional context in comments.

1 Comment

The crux of my question has to do with the fact that the nullable Gender field isn't being validated. I'm just including the explicit validation "results" to compare. The code I've shown above is contrived to illustrate the inconsistency in the validation. My Application_Start method includes the code you've noted above so Fluent Validation is fully integrated as the validation provider.

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.