

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