Creating your first validator

Welcome back to the "Junior's Toolkit" series! After an introduction to FluentValidation, where I discussed how this library can revolutionize data validation in C#, it's time to move to the next level. Today, we'll focus on the practical aspect of this journey - Creating your first validator.

Validating Simple Data Types

Imagine a User class that will be the basis for validation:

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

The User class is simple but reflects typical requirements in business applications. Our task now is to ensure that the data entered into this model is correct.

Moving on to creating a validator, we create a UserValidator class that inherits from AbstractValidator<User> from FluentValidation:

using FluentValidation;

public class UserValidator : AbstractValidator<User>
{
    public UserValidator()
    {
        RuleFor(user => user.Name)
            .NotEmpty().WithMessage("Name is required.");

        RuleFor(user => user.Email)
            .NotEmpty().WithMessage("Email is required.")
            .EmailAddress().WithMessage("Invalid email format.");

        RuleFor(user => user.Age)
            .InclusiveBetween(18, 99)
            .WithMessage("Age must be between 18 and 99.");
    }
}

In UserValidator, we define rules that check whether Name and Email are not empty and whether Email has the right format. Additionally, we set a rule for Age to ensure this value falls within a specified range. The WithMessage method is used to define custom error messages that are displayed when the input does not meet the specified validation criteria, allowing for more precise feedback to the user.

After defining the validator, we can use it to check if the User object meets our criteria:

var user = new User { Name = "John", Email = "john@example.com", Age = 25 };
var validator = new UserValidator();
var results = validator.Validate(user);

if (!results.IsValid)
{
    foreach (var failure in results.Errors)
    {
        Console.WriteLine($"Property {failure.PropertyName} failed validation. Error was: {failure.ErrorMessage}");
    }
}

In this example, if the user John does not meet the validation requirements, the program will return error information. This allows us to easily identify and correct problems with the input data.

When we call validator.Validate(user) on our user object, FluentValidation performs a series of checks according to the rules defined in the UserValidator class. The result of this operation is a ValidationResult object, which contains information about the outcome of the validation.

Key elements of this result include:

  • IsValid: This is a bool property that indicates whether the object passed all the validation rules without errors. If all rules are met, IsValid will be true. Otherwise, if any rule is not met, IsValid will be false.

  • Errors: This is a collection containing the details of the validation errors. Each item in this collection is a ValidationFailure object that provides information such as PropertyName (the name of the property that failed validation), ErrorMessage (the error message), and possibly other details related to the error.

In our code, we check whether the validation result (results) is invalid (!results.IsValid). If so, we iterate through the results.Errors collection, printing information about each error. This allows us to understand which data elements do not meet the specified criteria and require correction.

Thanks to this methodology, FluentValidation not only ensures data correctness but also offers clear and precise feedback that can be used to inform the user about the need to improve the entered data.

In summary, in this post, I presented the basics of creating your first validator in FluentValidation. Starting from defining the User model class, I showed how to construct the UserValidator using common validation rules such as NotEmpty, EmailAddress, and InclusiveBetween. Then, I illustrated how to use the Validate method to assess the correctness of the data, emphasizing the importance of the IsValid property and the details of errors contained in Errors. This section serves as a solid foundation for understanding and applying data validation in .NET applications using FluentValidation.

In future posts, we will look at validators provided by the FluentValidation library.

See you in the next posts!