Validation in .NET Core using FluentValidation

In any application, data validation is a critical aspect of ensuring data integrity and preventing errors. In .NET Core applications, handling data validation has become more straightforward and expressive with the help of FluentValidation. FluentValidation is a widely used library that allows you to define and apply validation rules in a fluent and readable manner. In this blog post, we'll explore how to use FluentValidation to simplify data validation in your .NET Core projects.

What is FluentValidation?

FluentValidation is an open-source library for .NET that provides a more expressive and maintainable way to perform data validation. It's especially popular in ASP.NET Core applications, where validating user inputs in forms, API requests, or any other data is a common requirement. FluentValidation allows you to define validation rules using a fluent and declarative syntax, making your validation logic easy to understand and maintain.

Getting Started with FluentValidation

To get started with FluentValidation in your .NET Core project, follow these steps:

The tools that I used for this sample project.

  1. VS 2022 Community Edition
  2. Web API
  3. FluentValidation NuGet Package
  4. .NET 6.0

The source code can be downloaded from GitHub.

Step 1. Install the FluentValidation NuGet Package

Begin by installing the FluentValidation NuGet package in your project. You can use the Package Manager Console or add it to your project file, as shown in the previous section.

Install-Package FluentValidation

Step 2. Create Validation Rules

Next, create validation rules by defining validator classes that inherit from AbstractValidator<T>. These classes specify how the validation should be performed for a particular data type T. For example.

public class PersonValidator:AbstractValidator<Person>
{
    public PersonValidator()
    {
        RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required");
        RuleFor(x => x.Age).InclusiveBetween(18,60).WithMessage("Age must be between 18 and 60");
        RuleFor(x => x.EmailAddress).NotEmpty().WithMessage("Email is required");
        RuleFor(x => x.EmailAddress).EmailAddress().WithMessage("Email is not valid");
    }
}

Step 3. Register the Validators in the Program.cs

Register a validator with the service provider.

builder.Services.AddScoped<IValidator<Person>, PersonValidator>();

Step 4. Use Validation in Your Code

In your application code, use the validator to validate your data objects, for example, in an ASP.NET Core controller action.

namespace FluentValidationTutorial.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PersonController : ControllerBase
    {
        private readonly IValidator<Person> validation;

        public PersonController(IValidator<Person> validation)
        {
            this.validation = validation;
        }

        [HttpPost("createperson")]
        public async Task<IActionResult> CreatePerson([FromBody] Person person)
        {
            var result = await this.validation.ValidateAsync(person);

            if (!result.IsValid)
            {
                return BadRequest(result.ToDictionary());
            }

            return Ok("Person created successfully!");
        }
    }
}

//An extension method has been added to group error messages.
public static class FluentValidationExtension
{
    public static IDictionary<string, string[]> ToDictionary(this ValidationResult validationResult)
    {
        return validationResult.Errors
          .GroupBy(x => x.PropertyName)
          .ToDictionary(
            g => g.Key,
            g => g.Select(x => x.ErrorMessage).ToArray()
          );
    }
}

Step 5. Handle Validation Errors

If validation fails, FluentValidation provides detailed error messages that you can use to populate your ModelState or handle errors in any way you prefer. The IsValid property of the ValidationResult object indicates whether the data is valid or not.

Advantages of Using FluentValidation

FluentValidation offers several advantages when it comes to data validation in .NET Core.

  • Readability: The fluent and declarative syntax makes your validation rules easy to read and understand, even for complex scenarios.
  • Separation of Concerns: By encapsulating validation rules in separate validator classes, you achieve better separation of concerns in your codebase.
  • Reusability: Validator classes can be reused across different parts of your application, promoting code reusability.
  • Customization: FluentValidation provides a wide range of built-in validation rules, but you can easily create custom validators to suit your specific needs.
  • Localization: It supports the localization of error messages, making it easy to create multilingual applications.

Conclusion

FluentValidation is a powerful tool for simplifying data validation in .NET Core applications. It offers a clean and expressive way to define and enforce validation rules, leading to more maintainable and robust code. Whether you're building web applications, APIs, or any other type of .NET Core project, FluentValidation can help you ensure the integrity of your data and provide a better user experience.

To get started with FluentValidation, simply install the NuGet package and begin creating your validator classes. Your code will become more organized, and your data validation logic will be easier to manage. Happy coding!