NashTech Blog

Introduction to Fluent Validation in .NET

Table of Contents
person using silver macbook pro

Form Validation: Importance

Form validation is crucial for web development, as it ensures accuracy and completeness of the user-submitted data. It also enhances the user experience by providing instant feedback. Beyond user satisfaction, validation also protects against errors and contributes to data integrity. This article shows how checking forms makes good and easy-to-use apps, and why it is important for web development.

Introduction

This guide explains the importance of Fluent Validation and its integration into the .NET Framework. You will discover the effectiveness of this library for validating user input, which will enhance the robustness of your applications. This guide offers a clear path to understanding the fundamentals of Fluent Validation and its role in optimizing the validation process within your .NET projects.

Overview

Fluent Validation is a powerful library designed to streamline and simplify the process of validating user inputs in applications. It offers a clear, expressive syntax, making it easy for developers to define and enforce validation rules. With Fluent Validation, validating forms and user data becomes an intuitive and efficient task, contributing to cleaner and more maintainable code in .NET projects. Its ease of use makes it a valuable tool for ensuring data integrity and enhancing the overall quality of .NET applications.


Integration in .NET Projects

Integrating Fluent Validation into your .NET project is a straightforward process, the simplest way is to use the dotnet CLI from a terminal window. Type the following snippet in your dotnet CLI terminal window to install the FluentValidation library.

dotnet add package FluentValidation

If you want to integrate it with your ASP.NET Core project, you can install the FluentValidation.AspNetCore package from Visual Studio. If you want to do the same via CLI, use the following snippet.

dotnet add package FluentValidation.AspNetCore

Rule Crafting: Creating Your First Validator

To create a collection of validation rules for a specific object, you should define a class that derives from AbstractValidator<T>, with T representing the class type you want to validate.
For example, we have an Employee Class:

public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public AccountDetails AccountDetails { get; set; }
}

To define your validation rules, this class should inherit from AbstractValidator<Employee> as follows:

using FluentValidation;
public class EmployeeValidator : AbstractValidator<Employee>
{
public EmployeeValidator()
{
RuleFor(employee => employee.Id).NotNull();
}
}

Employee employee = new Employee();
EmployeeValidator validator = new EmployeeValidator();
ValidationResult result = validator.Validate(employee);

From the above code, we can conclude the following:
I) The validation rules should be written inside the constructor.
II) In order to specify a rule, call the RuleFor method for the property you want to validate.
III) To execute the validator, instantiate the validator object and call the Validate method (passing employee object as a parameter)

Once the validation is done, let’s get to the return type of Validate method, which returns a ValidationResult object. This object contains 2 properties:
I) IsValid – Boolean stating the validation succeeded or not.
II) Errors – Collection of ValidationFailure objects depicting validation failure details

Advanced Validation Techniques

Validation across classes

In the given example, we have two different classes, Employee and AccountDetails:

public class Employee 
{
public string Name { get; set; }
public AccountDetails AccountDetails { get; set; }
}

public class AccountDetails
{
public string AccountNum { get; set; }
public string IFSCCode { get; set; }
public string MICRCode { get; set; }
public string BankName { get; set; }
public string BranchCode { get; set; }
}
public class AccountValidator : AbstractValidator<Address> 
{
public AccountValidator()
{
RuleFor(account => account.AccountNum).NotNull();
RuleFor(account => account.BranchCode).NotNull();
}
}

public class EmployeeValidator : AbstractValidator<Employee>
{
public EmployeeValidator()
{
RuleFor(employee => employee.Name).NotNull();
RuleFor(employee => employee.AccountDetails).SetValidator(new AccountValidator());
}
}

From the above code snippets, we can draw the following points:
I) We defined an AccountValidator with the rule that AccountNum and BranchCode should not be null.
II) Then we used the AccountValidator in EmployeeValidator definition.
III) Hence, when the Validate method on EmployeeValidator will be called, both the validators (EmployeeValidator and AccountValidator) will be applied, and the result will be a single ValidationResult of the combined validators.

Custom Validators: Tailoring to Your Needs

The following approaches can be used to define custom validators:

Predicate Validator

Must method use PredicateValidator which can be used to implement a custom validator. Take a look at the example given below:

public class Student {
public IList<Course> Courses {get;set;} = new List<Course>();
}
public class StudentValidator : AbstractValidator<Student> {
public StudentValidator() {
RuleFor(x => x.Courses).Must(list => list.Count < 5)
.WithMessage("The list must contain less than 5 courses");
}
}

public static class MyCustomValidators {
public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num) {
return ruleBuilder.Must(list => list.Count < num).WithMessage("The list contains too many courses");
}
}

RuleFor(x => x.Courses).ListMustContainFewerThan(5);

Let’s understand the above code from the points given below:
I)We created the Student class.
II) Created a validator (StudentValidator) using Must keyword to make sure our list contains at most 5 items.
III) In order to use the same validator logic again, we wrapped it in an extension method that acts upon any List with Type <T>

Troubleshooting Validation Issues

Even with a robust validation framework like Fluent Validation, you might encounter issues during development or runtime. Understanding common issues and knowing how to troubleshoot them is important for a smooth validation experience.

1. Missing Validator Registration:

Issue – Validators not registered for the target classes.
Ensure that you have registered validators for your classes. Use the ValidatorExtensions.RegisterValidator method during application startup.

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Register validators
AssemblyScanner.FindValidatorsInAssemblyContaining<Startup>()
.ForEach(result => services.AddTransient(result.InterfaceType, result.ValidatorType));

// Other configurations...
}
}

2. Conditional Validation Issues:

Issue – Conditional validations not working as expected.
Ensure that conditional validations are set up correctly. Use the When method for conditional rules:

public class OrderValidator : AbstractValidator<Order>
{
public OrderValidator()
{
RuleFor(order => order.ShippingAddress).NotEmpty().When(order => order.RequiresShipping);
// Add other rules...
}
}

Conclusion

Throughout this blog, we learnt about the definition, implementation, set-up of Fluent Validation, exploring its syntax, best practices, and the potential troubleshooting issues. It’s detailed understanding allows developers to create robust, maintainable, and error-resistant validation logic. By addressing common issues such as missing validator registration, conditional validation issues etc. developers can protect their applications against data inconsistencies and enhance the overall user experience.

References

Official Fluent Validation Documentation – https://docs.fluentvalidation.net/en/latest/index.html

Picture of Shivam Mathur

Shivam Mathur

I'm a Software Engineer with over 3 years of experience in Software Development. Skilled in designing and developing robust Windows and Web applications using .NET. Proficient in C#, .NET Core/Framework & Angular with a proven track record of delivering high-quality software solutions.

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top