Data Validation in C# (.NET): The Powerful FluentValidation Tool
Data validation is one of the key aspects of developing secure and reliable applications in C# (.NET). Whether you are creating a web API in ASP.NET Core, a desktop application in WPF, or a console utility, input data validation helps avoid errors, SQL injections, and incorrect system behavior. In this article, we will take a detailed look at the FluentValidation library — a modern, flexible, and widely used tool for validation in the .NET ecosystem.
What is FluentValidation and why is it needed?
FluentValidation is an open-source library for .NET that allows you to describe object validation rules using a fluent interface (method chaining). Unlike the built-in DataAnnotations attributes, FluentValidation:
- Separates validation logic from the data model — rules are placed in separate validator classes.
- Supports complex scenarios — conditional checks, custom rules, cross-property validations.
- Integrates with ASP.NET Core — automatically validates models in controllers.
- Simplifies testing — validators can be easily isolated and covered with unit tests.
Installation and Setup
To get started, install the package via NuGet Package Manager or .NET CLI:
dotnet add package FluentValidationIf you are using ASP.NET Core, add validator registration in Program.cs (or Startup.cs):
builder.Services.AddValidatorsFromAssemblyContaining<MyValidator>();Creating a Simple Validator
Suppose we have a user model:
public class User{ public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public int Age { get; set; }}Let's create a validator inheriting from AbstractValidator<User>:
using FluentValidation;
public class UserValidator : AbstractValidator<User>{ public UserValidator() { RuleFor(user => user.Name) .NotEmpty().WithMessage("Name is required") .Length(2, 50).WithMessage("Name must be between 2 and 50 characters");
RuleFor(user => user.Email) .NotEmpty().WithMessage("Email is required") .EmailAddress().WithMessage("Invalid Email format");
RuleFor(user => user.Age) .InclusiveBetween(18, 120).WithMessage("Age must be between 18 and 120"); }}Now you can perform validation:
var validator = new UserValidator();var user = new User { Name = "A", Email = "invalid", Age = 15 };var result = validator.Validate(user);
if (!result.IsValid){ foreach (var error in result.Errors) { Console.WriteLine($"Error in {error.PropertyName}: {error.ErrorMessage}"); }}Advanced Features
1. Custom Rules (Custom validators)
You can write your own validation logic using the Must method or create a separate method:
RuleFor(user => user.Name) .Must(name => !string.IsNullOrEmpty(name) && name.All(char.IsLetter)) .WithMessage("Name must contain only letters");2. Conditional Validation
Validate properties only when certain conditions are met:
RuleFor(user => user.Email) .NotEmpty().When(user => user.Age > 18) .WithMessage("Email is required for adult users");3. Cross-Property Validation
Compare values of different properties:
RuleFor(user => user.Password) .Equal(user => user.ConfirmPa