Validating ASP.NET MVC Models with FluentValidation

While Data Annotations.aspx) approach is generally used for user input data validation, FluentValidation that I’m going to introduce in this article might be better for delelopers with more benefits. Source code used in this post can be found at:

Typical User Input Data Validation with Data Annotations

Generally, for user input validation, data annotations approach like below is used. Each property that needs to be validated is required to have attribute classes:

public class RegisterViewModel
{
  [Required]
  [DataType(DataType.EmailAddress)]
  [Display(Name = "Email")]
  public string Email { get; set; }

  [Required]
  [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
  [DataType(DataType.Password)]
  [Display(Name = "Password")]
  public string Password { get; set; }

  [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
  [DataType(DataType.Password)]
  [Display(Name = "Confirm password")]
  public string ConfirmPassword { get; set; }
}
`</pre>

Attribute classes like `Required`, `StringLength` and `Compare` are responsible for data validation. If we use them, `ModelState.IsValid` value in the controller can be either `true` (valid) or `false` (invalid).

<pre>`[HttpPost]
public virtual async Task&lt;ActionResult&gt; Register(RegisterViewModel form)
{
  var vm = form;
  if (ModelState.IsValid)
  {
    vm.Validated = true;
  }
  return View(vm);
}
`</pre>

It's perfectly OK for data validation. However, personally, this looks too verbose to me. I need a single point for data validation. If you are like me, [`FluentValidation`](https://github.com/JeremySkinner/FluentValidation) will be yours. Let's change this model using `FluentValidation`

## User Input Data Validation with FluentValidation

You might need to download two packages from [NuGet](https://nuget.org):
  • FluentValidation
  • FluentValidation.MVC5

    Once you download both, then the RegisterViewModel class can be changed to:

    `[Validator(typeof(RegisterViewModelValidator))]
    public class RegisterViewModel
    {
      [Display(Name = "Email")]
      public string Email { get; set; }
    
      [DataType(DataType.Password)]
      [Display(Name = "Password")]
      public string Password { get; set; }
    
      [DataType(DataType.Password)]
      [Display(Name = "Confirm password")]
      public string ConfirmPassword { get; set; }
    }
    `

    As you can see, Validator(typeof(RegisterViewModelValidator)) has been added and Required, StringLength and Compare have been removed. Yes, that’s right. RegisterViewModelValidator defines all the validation rules like:

    `public class RegisterViewModelValidator : AbstractValidator<RegisterViewModel>
    {
      public RegisterViewModelValidator()
      {
        RuleFor(x => x.Email)
          .NotNull().WithMessage("Required")
          .EmailAddress().WithMessage("Invalid email");
    
        RuleFor(x => x.Password)
          .NotNull().WithMessage("Required")
          .Length(6, 100).WithMessage("Too short or too long");
    
        RuleFor(x => x.ConfirmPassword)
          .NotNull().WithMessage("Required")
          .Equal(x => x.Password).WithMessage("Not matched");
      }
    }
    `

    Once of benefits using FluentValidation is that setting validation rules looks very intuitive. For example, the Email property is required (Not NULL) and formatted as an email. In addition to this, each validation rule has its own error message when the validation fails. Once validators are defined, Application_Start() from Global.asax.cs should call FluentValidationModelValidatorProvider.Configure() to activate those validators defined.

    `public class MvcApplication : System.Web.HttpApplication
    {
      protected void Application_Start()
      {
        ...
    
        FluentValidationModelValidatorProvider.Configure();
      }
    }
    `

    Now, ModelState.IsValid property still has true or false after the validation. Let’s move on to setting up views.

    Setting up Views for User Input

    Corresponding Razore view might look like this:

    `@using (Html.BeginForm(MVC.Home.ActionNames.Register, MVC.Home.Name, FormMethod.Post))
    {
    <div>

    @Html.LabelFor(m =&gt; m.Email)
    &lt;div&gt;
      @Html.TextBoxFor(m =&gt; m.Email, new Dictionary&lt;string, object&gt;() { { "placeholder", "Email" } })
      @Html.ValidationMessageFor(m =&gt; m.Email)
    &lt;/div&gt;
    

    </div>
    <div>

    @Html.LabelFor(m =&gt; m.Password)
    &lt;div&gt;
      @Html.PasswordFor(m =&gt; m.Password, new Dictionary&lt;string, object&gt;() { { "placeholder", "Password" } })
      @Html.ValidationMessageFor(m =&gt; m.Password)
    &lt;/div&gt;
    

    </div>
    <div>

    @Html.LabelFor(m =&gt; m.ConfirmPassword)
    &lt;div&gt;
      @Html.PasswordFor(m =&gt; m.ConfirmPassword, new Dictionary&lt;string, object&gt;() { { "placeholder", "Confirm Password" } })
      @Html.ValidationMessageFor(m =&gt; m.ConfirmPassword)
    &lt;/div&gt;
    

    </div>
    <div>

    &lt;div&gt;
      &lt;input type="submit" name="Submit" /&gt;
    &lt;/div&gt;
    

    </div>
    }
    `

    This will be rendered in a web browser like:

    `<form action="/Home/Register" method="post">
      <div>
        <label for="Email">Email</label>
        <div>
          <input data-val="true" data-val-email="Invalid email" data-val-required="Required" id="Email" name="Email" placeholder="Email" type="text" value="" />
          <span class="field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"/>
        </div>
      </div>
      <div>
        <label for="Password">Password</label>
        <div>
          <input data-val="true" data-val-length="Too short or too long" data-val-length-max="100" data-val-length-min="6" data-val-required="Required" id="Password" name="Password" placeholder="Password" type="password" />
          <span class="field-validation-valid" data-valmsg-for="Password" data-valmsg-replace="true"/>
        </div>
      </div>
      <div>
        <label for="ConfirmPassword">Confirm password</label>
        <div>
          <input data-val="true" data-val-equalto="Not matched" data-val-equalto-other="*.Password" data-val-required="Required" id="ConfirmPassword" name="ConfirmPassword" placeholder="Confirm Password" type="password" />
          <span class="field-validation-valid" data-valmsg-for="ConfirmPassword" data-valmsg-replace="true"/>
        </div>
      </div>
      <div>
        <div>
          <input type="submit" name="Submit" />
        </div>
      </div>
    </form>
    `

    Therefore, the controller performs server-side validation. If you add a javascript validation library like jQuery Validation, client-side validation can also be easily developed.

    Setting up IoC Container for Dependency Injection for Validation

    Any validator using FluentValidation library inherits AbstractValidator&lt;T&gt; which implements the IValidator interface. It’s great because classes implementing interfaces can easily be both unit-testable and dependency-injectable. Let’s have a look how to setup IoC containers for those validators using Autofac. First of all, change Application_Start() from Global.asax.cs like below:

    `private void Application_Start(object sender, EventArgs e)
    {
      ...
    
      DependencyConfig.RegisterDependencies();
    }
    `

    As you can see, FluentValidationModelValidatorProvider.Configure() within the Application_Start() method has been replaced with DependencyConfig.RegisterDependencies(). DependencyConfig class under the App_Start directory might look like:

    `public static class DependencyConfig
    {
      public static void RegisterDependencies()
      {
        var builder = new ContainerBuilder();
    
        ...
    
        RegisterValidators(builder);
    
        var container = builder.Build();
    
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    
        RegisterValidationProviders(container);
      }
    
      private static void RegisterValidators(ContainerBuilder builder)
      {
        builder.RegisterType<RegisterViewModelValidator>()
               .Keyed<IValidator>(typeof(IValidator<RegisterViewModel>))
               .As<IValidator>();
      }
    
      ...
    }
    `

    For more details to build dependencies can be found at Autofac website. Instead, we’re focusing on two private methods – RegisterValidators() and RegisterValidationProviders(). All validator classes should go into the RegisterValidators() method for IoC registration. The RegisterValidationProviders() method actually activates validators implemented by FluentValidation library like:

    `private static void RegisterValidationProviders(IContainer container)
    {
      ModelValidatorProviders.Providers.Clear(); #1
      DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; #2
      var fvmvp = new FluentValidationModelValidatorProvider(new ValidatorFactory(container))
                  {
                    AddImplicitRequiredValidator = false,
                  }; #3
      ModelValidatorProviders.Providers.Add(fvmvp); #4
    }
    `
  • #1: There might be existing validator providers within memory. This clears the memory first.

  • #2: This explicitly declares to perform DataAnnotations model validation.
  • #3: This creates validators provided by FluentValidation using ValidatorFactory class. This also explicitly declares to perform validations.
  • #4: This adds validators using FluentValidation library.

    There might be many validator classes inheriting AbstractValidator&lt;T&gt; for each model. Therefore, all registered validators into Autofac should be instantiated by this ValidatorFactory class. Here’s the details:

    `public class ValidatorFactory : ValidatorFactoryBase
    {
      private readonly IContainer container;
    
      public ValidatorFactory(IContainer container)
      {
        this.container = container;
      }
    
      public override IValidator CreateInstance(Type validatorType)
      {
        var validator = container.ResolveOptionalKeyed<IValidator>(validatorType);
        return validator;
      }
    }
    `

    As stated above, this is possible because all validators implements IValidator interface. Once we completes this step, we should remove all [Validator(typeof(TValidator))] attribute classes on models. For this case, it will be [Validator(typeof(RegisterViewModelValidator))].

    Unit Testing Validators

    As IValidator interface gives us much flexibility, we can also perform unit tests. With NUnit and FluentAssertions, we can easily write unit tests.

    `[TestFixture]
    public class RegisterModelValidatorTest
    {
      private IValidator _validator;
    
      [SetUp]
      public void Init()
      {
        this._validator = new RegisterViewModelValidator();
      }
    
      [Test]
      [TestCase("email", "password", "password", false)]
      [TestCase(null, "password", "password", false)]
      [TestCase("e@mail.com", "password", "password", true)]
      public void RegisterViewModel_Should_Be_Validated(string email,
                                                        string password,
                                                        string confirmPassword,
                                                        bool expected)
      {
        var vm = new RegisterViewModel()
                     {
                       Email = email,
                       Password = password,
                       ConfirmPassword = confirmPassword,
                     };
        var result = this._validator.Validate(vm);
        result.IsValid.Should().Be(expected);
      }
    `

    Any validator implementing the IValidator interface has the Validate() method that actually performs the validation. Like above, the model is validated and tested. However, this conducts validation for whole properties in the model. If I want to test only one property, what can I do? FluentValidation provides a few helper methods for this case.

  • ShouldHaveValidationErrorFor()

  • ShouldNotHaveValidationErrorFor()
  • ShouldHaveChildValidator()

    Therefore, testing one property can be written like:

    `[Test]
    [TestCase("password", false)]
    [TestCase(null, true)]
    public void Password_Should_Be_Validated(string password, bool exceptionExpected)
    {
      var validator = this._validator as RegisterViewModelValidator;
      try
      {
        validator.ShouldNotHaveValidationErrorFor(p => p.Password, password);
      }
      catch (ValidationTestException ex)
      {
        if (exceptionExpected)
        {
          Assert.Pass();
        }
        else
        {
          Assert.Fail(ex.Message);
        }
      }
      catch (Exception ex)
      {
        Assert.Fail(ex.Message);
      }
    }
    `

    The Password property of the RegisterViewModel model has a validation rule in RegisterViewModelValidator class. Hence, it will be tested. The helper method, ShouldNotHaveValidationErrorFor(), will be passed, if the validation succeeds. However, if the validation fails, it will throw the ValidationTestException exception. If this is expected, it passes the test; otherwise it fails the test. Likewise, the ConfirmPassword property can be tested like below:

    `[Test]
    [TestCase(“password”, “password”, false)]
    [TestCase(“password”, “different”, true)]
    public void ConfirmPassword_Should_Be_Validated(string password, string confirmPassword, bool exceptionExpected)
    {
    var validator = this._validator as RegisterViewModelValidator;
    try
    {

    validator.ShouldNotHaveValidationErrorFor(
        p =&gt; p.ConfirmPassword,
        new RegisterViewModel() { Password = password, ConfirmPassword = confirmPassword });
    

    }
    catch (ValidationTestException ex)
    {

    if (exceptionExpected)
    {
        Assert.Pass();
    }
    else
    {
        Assert.Fail(ex.Message);
    }
    

    }
    catch (Exception ex)
    {

    Assert.Fail(ex.Message);
    

    }
    }

So far, we’ve take a brief look at using FluentValidation library for our ASP.NET MVC web app. Instead of scattering those validation rules all over the places, we can place them into one spot so that we can get benefits, in terms of maintainablilty.

One of downsides using FluentValidation is that it supports Web API with many limitations. Of course, we can validate models through Web API with many walkarounds. I don’t think, however, it’s efficient. According to the good news from the library creator/maintainer, Jeremy Skinner, he has been focusing on ASP.NET MVC 6 with new MVC/Web API features. So, we hope the next version of FluentValidation will fully support both MVC and Web API.