Fluent Validation is a popular .NET library that makes it easy to check if your objects have valid data. It’s like a set of rules you create to make sure your objects follow the correct format. The best part? It uses a clean and readable style that even beginners can understand.
In this guide, we’ll show you how to use Fluent Validation step-by-step, with examples for validating a Library and its Book objects. By the end, you’ll see how it can save time and make your code more organized.
Imagine you’re managing a library system. You want to ensure that:
Instead of writing lots of messy checks everywhere in your code, Fluent Validation lets you define these rules in one place using a simple, readable style.
First, you need to install the Fluent Validation library. Open your terminal and run:
dotnet add package FluentValidation
This adds Fluent Validation to your .NET Core project.
You need some basic classes for a library system. For example:
public class Library
{
public string Name { get; set; }
public Address Address { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public List Books { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
public class Book
{
public string BookId { get; set; }
public string Title { get; set; }
public string Author { get; set; }
}
A validator is where you define the rules for checking if your data is valid.
public class AddressValidator : AbstractValidator<Address>
{
public AddressValidator()
{
RuleFor(address => address.Street)
.NotEmpty().WithMessage("Street is required.");
RuleFor(address => address.City)
.NotEmpty().WithMessage("City is required.");
RuleFor(address => address.State)
.NotEmpty().WithMessage("State is required.");
RuleFor(address => address.ZipCode)
.Matches(@"^\d{5}(-\d{4})?$")
.WithMessage("Invalid ZIP code format.");
}
}
RuleFor
: Specifies which property to validate, like Street
or City
..NotEmpty()
: Makes sure the property isn’t blank..WithMessage()
: Sets a friendly error message..Matches()
: Uses a pattern (like a ZIP code format) to check if the value is correct.2. Library Validator
Next, validate the library itself:
public class LibraryValidator : AbstractValidator<Library>
{
public LibraryValidator()
{
RuleFor(library => library.Name)
.NotEmpty().WithMessage("Library name is required.");
RuleFor(library => library.Address)
.SetValidator(new AddressValidator()); // Use the AddressValidator
RuleFor(library => library.PhoneNumber)
.Matches(@"^\d{10}$")
.WithMessage("Invalid phone number format.");
RuleFor(library => library.Email)
.EmailAddress();
RuleFor(library => library.Books)
.NotEmpty().WithMessage("The library must have books.")
.Must(books => books.Count >= 5)
.WithMessage("At least 5 books are required.");
RuleForEach(library => library.Books)
.SetValidator(new BookValidator()); // Validate each book
}
}
.SetValidator()
: Lets you reuse the AddressValidator
to check the Address
property..EmailAddress()
: Ensures the email is in a valid format..Must()
: Adds a custom rule, like making sure the library has at least 5 books..RuleForEach()
: Validates each item in a collection (e.g., each Book
).3. Book Validator
Finally, validate the details of each book:
public class BookValidator : AbstractValidator<Book>
{
public BookValidator()
{
RuleFor(book => book.BookId)
.NotEmpty().WithMessage("Book ID is required.")
.Matches(@"^[A-Z0-9-]+$")
.WithMessage("Book ID must contain only uppercase letters, numbers, or hyphens.");
RuleFor(book => book.Title)
.NotEmpty().WithMessage("Book title is required.")
.Length(2, 100).WithMessage("Title must be between 2 and 100 characters.");
RuleFor(book => book.Author)
.NotEmpty().WithMessage("Author name is required.");
}
}
Extra Tip: Conditional Validation Sometimes, you need to apply rules only in specific cases. For example, if a book title is long, require an author:
When(book => book.Title.Length > 50, () =>
{
RuleFor(book => book.Author)
.NotEmpty().WithMessage("Author is required for long titles.");
});
Here’s how to validate a Library
object:
public void ValidateAndCreateLibrary(Library library)
{
var validator = new LibraryValidator();
var results = validator.Validate(library);
if (!results.IsValid)
{
foreach (var error in results.Errors)
{
Console.WriteLine($"Validation Error: {error.ErrorMessage}");
}
throw new ValidationException("Library data is invalid.");
}
// Proceed with creating the library
}
Validate()
: Checks the library
object against the rules in LibraryValidator
.results.Errors
: Lists all the problems if validation fails.ValidationException
: Stops the process if the data isn’t valid.Fluent Validation is a beginner-friendly way to ensure your .NET objects follow the correct format. It’s clean, reusable, and easy to expand as your project grows. By separating validation logic from the main code, it keeps everything organized and simple to maintain.