Fluent Validation with .NET Core
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.