How To Use FluentValidation in ASP.NET Core (.NET 6)
Tags: aspnetcore, dotnet, csharp, netcore
Published: 2023-06-08 22:01:46

FluentValidation is a popular validation library for .NET applications. It provides a fluent and expressive syntax for defining validation rules for our models. With FluentValidation, we can easily validate user input and ensure data integrity, reducing the chance of errors and improving the overall quality of our application.

The library supports a wide range of validation rules and features, including:

- Customizable Validation Rules
- Property-Level and Cross-Property Validation
- Error Messages and Localization
- Rule sets — group validation rules together
- Asynchronous Validation
- Custom Error Codes and Severity Level
- Testing Support and more.

It integrates seamlessly with ASP.NET Core, making it a versatile choice for implementing robust and maintainable validation logic in our .NET projects.

## How to Configure FluentValidation
Let’s follow the steps below in our ASP.NET Core Web API project:

## 1- Install the NuGet packages

```
Install-Package FluentValidation
Install-Package FluentValidation.DependencyInjectionExtensions
```

## 2-Register the Service
Once installed, we’ll need to modify our Startup class to include a call to **_AddFluentValidationAutoValidation()_**

```
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddFluentValidationAutoValidation();
```

This method must be called after **_AddMvc (or AddControllers/AddControllersWithViews)_**. Make sure you add **_using FluentValidation.AspNetCore_** to your startup file so the appropriate extension methods are available.

## 3-Define the Model

The following example will make use of a **_User_** object.

```
public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}
```

## 4-Create a Validator Class

Let’s create a validator class that inherits from **_AbstractValidator<T>_**, where **_T_** is our User class. Define the validation rules within the validator class.

```
using FluentValidation;

public class UserValidator : AbstractValidator<User>
{
    public UserValidator()
    {
        RuleFor(user => user.Name).NotEmpty().WithMessage("Name is required.");
        RuleFor(user => user.Age).InclusiveBetween(18, 99).WithMessage("Age must be between 18 and 99.");
    }
}
```

## 5-Register the Validator

If you’re using MVC, Web API, or Razor Pages you’ll need to register your validator with the Service Provider in the **_Startup_** class.

```
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddFluentValidationAutoValidation();
builder.Services.AddScoped<IValidator<User>, UserValidator>();
```

## 6-Usage

Unlike the manual validation example, we don’t have a reference to the validator directly. Instead, ASP.NET will handle invoking the validator and adding the error messages to **_ModelState_** before the controller action is invoked. Inside the action, we only need to check **_ModelState.IsValid_**

```
// Automatic validation
[HttpPost]
public IActionResult Create(User model)
{
     if (!ModelState.IsValid)
     {
        return StatusCode(StatusCodes.Status400BadRequest, ModelState);
     }

     // Continue with user creation process

     return StatusCode(StatusCodes.Status201Created, "User created successfully!");
}
```

When we make a POST request with the wrong name and age input, we then get returned the Error Validation Result.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fuj9daovt5r3x3tf1l6g.png)

In case you prefer to take a more explicit approach (manual validation), you have the option to specifically designate the class or model for which you want to create the validator. In this scenario, the **_Validate_** method would provide a **_ValidationResult_** object with two key attributes. The first is **_IsValid_**, a boolean indicating the success or failure of the validation process. The second attribute is **_Errors_**, which comprises a list of **_ValidationFailure_** objects containing detailed information about any encountered errors.

We can implement this as follows:

```
// Manual validation
[HttpPut]
public IActionResult Update(User user)
{
     var validationResult = _userValidator.Validate(user);
    
     if (!validationResult.IsValid)
     {
        return StatusCode(StatusCodes.Status400BadRequest, validationResult.Errors);
     }
    
     // Continue with user update process
    
     return StatusCode(StatusCodes.Status200OK, "User updated successfully!");
}
```
When we make a PUT request with an input error in the request, we then get returned the Error Validation Result.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9z8kagxskpze5e97hiuz.png)


_For more: https://github.com/FluentValidation/FluentValidation.AspNetCore_

---

## Final Thoughts

FluentValidation offers a compelling alternative to Data Annotations for model validation. It empowers developers with enhanced control over validation rules, resulting in code that is more readable and easier to test. By implementing FluentValidation, we can **_achieve a clearer separation of concerns, ensuring that validation logic remains distinct and manageable_**.

---

## Thanks for reading!
Through my articles, I share Tips & Experiences on web development, career, and the latest tech trends. Join me as we explore these exciting topics together. Let’s learn, grow, and create together!

➕More article about [Programming, Careers, and Tech Trends.](https://medium.com/@andytechdev)

🔔 Follow me on [Medium](https://medium.com/@andytechdev) | [Twitter ](https://twitter.com/andytechdev)