Blog Details

story

Fluent Validation in .NET: A Comprehensive Guide for Beginners

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.

What is Fluent Validation?

Imagine you’re managing a library system. You want to ensure that:

  • The library has a name.
  • Each book has a valid ID, title, and author.
  • The library has a valid address, phone number, and at least five books.

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.

Step 1: Set Up Fluent Validation

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.

Step 2: Define Your Models

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; }
}

Step 3: Create Validators

validator is where you define the rules for checking if your data is valid.

  1. Address Validator
    Let’s ensure an address has a street, city, state, and a valid ZIP code:
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.");
});

Step 4: Validating Your Data

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 vs Traditional validations

Conclusion

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.

We may use cookies or any other tracking technologies when you visit our website, including any other media form, mobile website, or mobile application related or connected to help customize the Site and improve your experience. learn more

Allow