Shawn Wildermuth

Using FluentValidation in ASP.NET Core


https://fluentvalidation.net/I'm working on an example to explore some more complex modeling in EF (for SQL and NoSQL) but that's not ready so I thought I'd use it as a bed for some Validation testing I'm doing. The result is some exploration of the FluentValidation project that I haven't had time to dig into until now.

Validation is an interesting exercise in ASP.NET (Core) and trying to get it correct is quite difficult. Ultimately in this day of SPAs and mobile apps, we need a solution that handles the client and the server. If you don't validate on the server it just doesn't matter.

Using FluentValidation

FluentValidation is a replacment for the existing validation attributes (DataAnnotations) that you might already be using. The idea is to separate the validation from the classes. To be clear, this doesn't replace setting up your Entity Framework types with Fluent API this is about server-side validation only. Think of it as a clearer way to define rules for validation of your models or DTOs.

NOTE: FluentValidation works with ASP.NET Core, ASP.NET MVC and ASP.NET Web API. My example is in ASP.NET Core.

To get started you'll need to add the FluentValidation Nuget package:

dotnet add package FluentValidation

This package will just let you setup validations that you can use outside of ASP.NET, but it's the core functionality. For integration into ASP.NET Core you'll need to add the glue package too:

dotnet add package FluentValidation.AspNetCore

Now that you have them both, let's start with the glue to allow you to use it inside of Model Binding in ASP.NET Core:

services.AddControllersWithViews() // Could be AddController or AddMvc too
        .AddFluentValidation(opt =>
        {
          opt.RegisterValidatorsFromAssembly(Assembly.GetExecutingAssembly());
        });

This adds FluentValidation to the pipeline for Controllers and Views. Inside the options for the FluentValidation, there are a number of options (like passing in a single assembly), but I like to RegisterValidatorsFromAssembly to pick the assembly I'm containing my assembly in. In this example there is just one assembly, so I'm using GetExecutingAssembly.

This is effectively scanning the classes for any that are Validators. Let's create a validation class next to see what it's actually looking for.

Let's assume that you want to create validators for a model class like this:

  public class BountyHunterModel
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
    public int Age { get; set; }
    public IEnumerable<BountyModel> CollectedBounties { get; set; }
  }

I'd derive a new class from AbstractValidator with the BountyHunterModel as a generic argument:

  public class BountyHunterModelValidator 
    : AbstractValidator<BountyHunterModel>
  {
  }

Then in the constructor you'll simply create rules for attributes:

public BountyHunterModelValidator()
{
  // Validate Scalar Types
  RuleFor(c => c.Age).InclusiveBetween(0, 1000);
  RuleFor(c => c.Name).NotEmpty()
                      .MaximumLength(250); // Long Star Wars Names
  RuleFor(c => c.Title).MaximumLength(100); // Can be empty

  // Validate Collections
  RuleForEach(c => c.CollectedBounties).NotEmpty(); 
}

In doing this, these validations will simply be used to in Model Binding to do the validation of your Models. I'll have a more comprehensive example posted in the next week or so, but this should get you started!

You can see the docs at:

FluentValidation