Overview Of Fluent Validation In ASP.NET MVC

Data Validation is a key feature of any Web Application. Validating properly to the UI component helps us in avoiding error prone data and gives the user proper information regarding what they are supposed to enter. In Web Applications, it avoids different security threats like SQL injections and script injections.

We already know that we have different validation frameworks given by .NET framework, we  can validate the UI components, using JavSscript, jQuery, in client side.

In ASP.NET MVC, Data Annotation validation is used to validate the page. It is easy to use the validation rules and pass the error message to the UI fields. The problem in it is the validation rules, which are attached to the view model.

In a large ASP.NET MVC Application, we separate the Entity from View Model. The domain entities are related to all the Applications but View Models are specific to an Application. We practically use the fields, which are needed in the Application and not the total domain entity. We use Automapper to map domain entity to view model to make the View Model clean and simple. When we put validation condition in the View Model, it becomes complicated.

If the Application is a large scale enterprise Application, we have messed up the validations and model in a single class. Here, we are violating the design principle separation of the concern and single responsibility principle. This causes a problem with a test driven development promise to the customer and all our code is not covered in the test.
 
 

To overcome this type of problem, we have an option, which is a third party Validation framework called Fluent validation.

We can separate the validation rules completely from the underlying model. Fluent validation library provides some easy way to unit test the validation rules; it will be helpful, when we need to inject dependencies into our validation rules.

For example, we can read some information from the database or external sources to validate UI fields and show the error message to the users. When there is a need of separating the validation logic from Model property, keep the design rules of single responsibility and separation of concerns. Fluent validations are easy as far as unit testing is concerned and we can inject the dependency or we can make a database call or any Service call to validate a property.

It supports a lot of built-in rules, error messages localization, using object data in the error messages, custom validation methods and conditional validation - applying some rules, if the object data matches a condition, rule sets - apply named set of rules, validation of aggregated objects, collections and property names would be compatible with ASP.NET MVC property names and so on.

It gives the better control validation rules, separates the validation from my View Models and makes Unit testing easier and a clean separation.

Let us create a project and understand in detail about Fluent validation.

 
 
 
 

Create the EmployeeModel, as shown below-
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5.   
  6. namespace FluentValidationDemo.Models  
  7. {  
  8.     public class EmployeeModel  
  9.     {  
  10.         public int EmployeeId { getset; }  
  11.         public string EmployeeName { getset; }  
  12.   
  13.         public string DepartmentNo { getset; }  
  14.         public string Address { getset; }  
  15.         public int Salary { getset; }  
  16.   
  17.         public string Email { getset; }  
  18.     }  
  19. }  
Create a Class named EmployeeValidator and the code for EmployeeValidator, as shown below-
  1. using FluentValidation;  
  2. using FluentValidationDemo.Models;  
  3. using System;  
  4. using System.Collections.Generic;  
  5. using System.Linq;  
  6. using System.Web;  
  7.   
  8. namespace FluentValidationDemo  
  9. {  
  10.     public class EmployeeValidator : AbstractValidator<EmployeeModel>  
  11.     {  
  12.         public EmployeeValidator()  
  13.         {  
  14.   
  15.             EmployeeEntities e = new EmployeeEntities();  
  16.            
  17.                
  18.             RuleFor(x => x.EmployeeId).NotEmpty().WithMessage("EmployeeId is required");  
  19.             RuleFor(x => x.EmployeeName).NotEmpty().WithMessage("EmployeeName is required");  
  20.   
  21. EmployeeEntities e = new EmployeeEntities();  
  22.             Custom(model =>  
  23.             {  
  24.                 var employeevalidation = e.Employees.FirstOrDefault(emp => emp.EmployeeName == model.EmployeeName);  
  25.                 if (employeevalidation != null)  
  26.                 {  
  27.                     return new FluentValidation.Results.ValidationFailure("EmployeeName", model.EmployeeName+"is a Existing employee.");  
  28.                 }  
  29.   
  30.                 return null;  
  31.             });  
  32.   
  33.             RuleFor(x => x.EmployeeName).Length(10,20).WithMessage("Name should be between 10 and 20 characters");  
  34.             RuleFor(x => x.DepartmentNo).NotEmpty().WithMessage("DepartmentNo is not valid");  
  35.   
  36.             RuleFor(x => x.Address).NotEmpty().WithMessage("Address is required");  
  37.             RuleFor(x => x.Salary).NotEmpty().WithMessage("Salary is not valid");  
  38.   
  39.             RuleFor(x => x.Email)  
  40.               .Matches(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").WithMessage("Not  a valid email")  
  41.               .NotEmpty();  
  42.             Custom(model=>  
  43.                 {  
  44.                     var employeevalidation=e.Employees.FirstOrDefault(emp=>emp.Email==model.Email);  
  45.                     if(employeevalidation!=null)  
  46.                     {  
  47.                         return new FluentValidation.Results.ValidationFailure("Email""Email is already in Use Please try another EMail ");  
  48.                     }  
  49.   
  50.                     return null;  
  51.                  });  
  52.                
  53.         }  
  54.     }  
  55. }  
EmployeeValidator class takes EmployeeModel as an input: AbstractValidator<EmployeeModel>. Here, we are applying different validation rules like required fields, length, range, regular expression for EmployeeModel.
  1.    
  2. RuleFor(x => x.EmployeeId).NotEmpty().WithMessage("The EmployeeId field is required");  
  3.   
  4. RuleFor(x => x.EmployeeName).NotEmpty().WithMessage("EmployeeName is required");  
 

We can validate the data from the database Server and check certain values before the user saves those values. For example, Email or username, which can be a duplicate can be avoided, using a database call in a Fluent validation rules, which are given below-
  1. EmployeeEntities e = new EmployeeEntities();  
  2. Custom(model =>   
  3. {  
  4.     var employeevalidation = e.Employees.FirstOrDefault(emp => emp.EmployeeName == model.EmployeeName);  
  5.     if (employeevalidation != null)  
  6.     {  
  7.         return new FluentValidation.Results.ValidationFailure("EmployeeName", model.EmployeeName + "is a Existing employee.");  
  8.     }  
  9.     return null;  
  10. });  

Here, we are calling EmployeeEntities, which is an entity from a employee table from the database. 

 
Hope you got the information on Fluent validation. Thank you for reading.