Fluent Validation with .NET Core

Lucas Andrade
3 min readNov 14, 2023

--

Introduction

As a software engineer working with .NET Core, you understand the importance of robust data validation in your applications.

Fluent Validation is a powerful library that simplifies the process of validating objects fluently and expressively.

In this article, we’ll explore what Fluent Validation is, how to install it, and dive into various use cases.

Installing Fluent Validation

Package Manager Console

Open the Package Manager Console and run the following command to install Fluent Validation:

Install-Package FluentValidation

.NET CLI

If you prefer the command line, use the following .NET CLI command.

dotnet add package FluentValidation

Creating a Validator

Validators in Fluent Validation are classes that define rules for validating objects. Let’s create a simple validator for a hypothetical User class. Start by creating a class named UserValidator:

using FluentValidation;

public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(user => user.FirstName)
.NotEmpty()
.WithMessage("First name is required.");
RuleFor(user => user.LastName)
.NotEmpty()
.WithMessage("Last name is required.");
RuleFor(user => user.Email)
.EmailAddress()
.WithMessage("Invalid email address.");
}
}

In this example, we’ve created a validator for the User class with rules for the FirstName, LastName, and Email properties.

Now we add the configuration to our Program.cs which should look like this:

builder.Services.AddFluentValidationAutoValidation()
.AddFluentValidationClientsideAdapters()
.AddValidatorsFromAssemblyContaining<UserValidator>();

Note that this configuration gets the assembly of the validator passed and adds every validator on that assembly, meaning that this configuration is only done once, not for every validator you create.

Using the Validator

1. Using Fluent Validation with ModelState in a Controller Endpoint

Let’s see how to use the validator in a controller endpoint. Consider the following example:

[ApiController]
[Route("api/users")]
public class UserController : ControllerBase
{
[HttpPost]
public IActionResult CreateUser([FromBody] User user)
{
if (!ModelState.IsValid)
{
var messages = ModelState
.SelectMany(modelState => modelState.Value.Errors)
.Select(err => err.ErrorMessage)
.ToList();

return BadRequest(messages);
}

// Process valid user data
// ...

return Ok("User created successfully");
}
}

2. Implementing a Filter to Validate ModelState

Fluent Validation seamlessly integrates with ASP.NET Core’s ModelState validation.

For us not to check the ModelState every time we want to check a validator, we can create a filter to automatically validate the ModelState using the UserValidator:

public class ValidationFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context) { }

public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var messages = context.ModelState
.SelectMany(message => message.Value.Errors)
.Select(error => error.ErrorMessage)
.ToList();

context.Result = new BadRequestObjectResult(messages);
}
}
}

To use a filter, first, we need to configure it. So we must add options to our controller configuration on the Program.cs, so we get the following code:

builder.Services.AddControllers(options => options.Filters
.Add(typeof(ValidationFilter)));

3. Using Fluent Validation in a Service with Dependency Injection

Fluent Validation works seamlessly with dependency injection. Inject the IValidator<User> interface into your service and use it for validation:

public class UserService
{
private readonly IValidator<User> _userValidator;

public UserService(IValidator<User> userValidator)
{
_userValidator = userValidator;
}

public bool ValidateUser(User user)
{
var validationResult = _userValidator.Validate(user);
return validationResult.IsValid;
}
}

Instead of returning a ValidationResult, you can alternatively tell FluentValidation to throw an exception if validation fails by using the ValidateAndThrow:

public void ValidateUser(User user)
{
_userValidator.ValidateAndThrow(user);
}

Fluent Validation Functionalities

Fluent Validation provides a rich set of functionalities. Here are some key methods that can be used in a validator:

  • RuleFor: Defines a rule for a specific property.
  • NotEmpty: Ensures that the property is not empty.
  • WithMessage: Specifies a custom error message for the validation rule.
  • EmailAddress: Validates that the property is a valid email address.
  • RuleForEach: Applies a rule to each element of a collection property.

These are just a few examples, and Fluent Validation offers many more methods and options for building complex validation rules.

For a deep understanding of its features, check the Fluent Validation docs: https://docs.fluentvalidation.net/en/latest/index.html

Conclusion

Fluent Validation is a versatile and feature-rich library that simplifies the process of data validation in .NET Core applications.

Whether you’re validating data in a controller, implementing filters, or using it within a service with dependency injection, Fluent Validation provides a clean and expressive way to handle validation logic in your applications.

By understanding its functionalities and leveraging its capabilities, you can ensure that your application’s data is validated effectively and reliably.

--

--