Creating Your Own Validation Attribute In MVC And Web API 2.0

In this article, we will learn how to create your own validation attribute in MVC and WebAPI 2.0.

Data validation in an Appliction is one of the major task for the developer now-a-days. Data validation is the process of ensuring that the data entered by any users is correct and is a useful data. It uses routines, often called validation rules, validation constraints or check routines, which checks for correctness, meaningfulness and security of the data, which is input to the Web Application.These rules are mainly implemented in UI, business logic and in the database label.

If we check in any Web Application, we will found mainly the validations in UI label. As the user interface is the primary source, where the user can enter an invalid data to the Application, we mainly focus on UI validation.

In MVC, we have Dataanotations attributes, which will ensure data integrity while entering to the Application.

All DataAnnotation attributes are included in System.ComponentModel.DataAnnotations namespace. Various DataAnnotation attributes gives you a simple way to perform the validation on model data. These attributes are helpful for the common validation pattern like Required, Range, StringLength etc.

It can perform the validation on both client and Server side.

The main Data Validation attributes are given below.
  1. Required - It ensures that the value must be provided to the model property.
  2. Range- The data should be in specific range like age should not be between 1 to 18.
  3. StringLength- You can specify the minimum and maximum length of property value.
  4. Compair- It is used to compare one property value with another.
  5. Regular Expression- The value should match regular expression e.g. E-mail, phone, URL etc.
However sometimes when these validators fails to validate certain business rules; we require custom validation for custom business rules.
Hence, we will see how can we implement these in MVC Application.
 
Requirement

Here, I have a model, as shown below.
  1. public class RegisterViewModel  
  2.    {  
  3.        [Required]  
  4.        [EmailAddress]  
  5.        [Display(Name = "Email")]  
  6.        public string Email { getset; }  
  7.   
  8.        [Required]  
  9.        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]  
  10.        [DataType(DataType.Password)]  
  11.        [Display(Name = "Password")]  
  12.        public string Password { getset; }  
  13.        [Required(ErrorMessage ="First Name is Required")]  
  14.        public string FirstName { getset; }  
  15.        [Required(ErrorMessage = "Last Name is Required")]  
  16.        public string LastName { getset; }  
  17.        
  18.         
    • public string Country { get; set; }
  19.   
  20.   
  21.    }  
Thus, I have a country property. Here, I want to implement the validation.The  Application should accept only these 3 countries like (India,Pakistan,Nepal).

As of now, I don't find any validation attribute, which will fulfill my requirement, so I will go for Custom Validation.

Before implementing Custom Validation, we shold know about a class i.e. ValidationAttribute.

ValidationAttribute class is an abstract class, which contains IsValid virtual method. IsValid method takes the value and ValidationContext object as the input parameters.

Value represents the value of the model property for which this Custom Validation applies. ValidationContext describes the context in which validation check is performed.

Thus, for this custom validation, add a new class called checkCountry as shown below and derive it from ValidationAttribute class.
  1. public class CustomValidation  
  2.     {  
  3.         public sealed class checkCountry : ValidationAttribute  
  4.         {  
  5.             public String AllowCountry { getset; }  
  6.   
  7.             protected override ValidationResult IsValid(object country, ValidationContext validationContext)  
  8.             {  
  9.                 string[] myarr = AllowCountry.ToString().Split(',');  
  10.                 if(myarr.Contains(country))  
  11.                 {  
  12.                     return ValidationResult.Success;  
  13.                 }  
  14.                 else  
  15.                 {  
  16.                     return new ValidationResult("Please choose a valid country eg.(India,Pakistan,Nepal");  
  17.                 }  
  18.             }  
  19.   
  20.         }  
  21.      
  22.     }   
Now, use the namespace given below and modify the model, as shown below.
  1. using System.ComponentModel.DataAnnotations;  
  2. using static customValidation.CustomValidation;  
Now, you have the attributes checkcountry in the model property, as shown.
  1. [checkCountry(AllowCountry ="India,Pakistan,Nepal",ErrorMessage = ("Please choose a valid country eg.(India,Pakistan,Nepal")]  
  2.        public string Country { getset; }  
Now, add the details given below and click Register in View.



Here, the source code for View is given below.
  1. @model customValidation.Models.RegisterViewModel  
  2. @{  
  3. //ViewBag.Title = "Register";  
  4. }  
  5.   
  6. <h2>@ViewBag.Title.</h2>  
  7.   
  8.   
  9.   
  10. @using (Html.BeginForm("Register""Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))  
  11. {  
  12.     @Html.AntiForgeryToken()  
  13.     <h4>Create a new account.</h4>  
  14.     <hr />  
  15.     @*@Html.ValidationSummary(""new { @class = "text-danger" })*@  
  16.     <div >  
  17.         <div class="form-group" >  
  18.             @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })  
  19.             <div class="col-md-10">  
  20.                 @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })  
  21.                @Html.ValidationMessageFor(model => model.Email,nullnew { @class = "text-danger" })   
  22.             </div>  
  23.         </div>  
  24.         <div class="form-group">  
  25.             @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })  
  26.             <div class="col-md-10">  
  27.                 @Html.PasswordFor(m => m.Password, new { @class = "form-control" })  
  28.                 @Html.ValidationMessageFor(model => model.Password, nullnew { @class = "text-danger" })  
  29.             </div>  
  30.         </div>  
  31.         <div class="form-group">  
  32.             @Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" })  
  33.             <div class="col-md-10">  
  34.                 @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" })  
  35.                 @Html.ValidationMessageFor(model => model.FirstName, nullnew { @class = "text-danger" })  
  36.             </div>  
  37.         </div>  
  38.         <div class="form-group">  
  39.             @Html.LabelFor(m => m.LastName, new { @class = "col-md-2 control-label" })  
  40.             <div class="col-md-10">  
  41.                 @Html.TextBoxFor(m => m.LastName, new { @class = "form-control" })  
  42.                 @Html.ValidationMessageFor(model => model.LastName, nullnew { @class = "text-danger" })  
  43.             </div>  
  44.         </div>  
  45.         <div class="form-group">  
  46.             @Html.LabelFor(m => m.Country, new { @class = "col-md-2 control-label" })  
  47.             <div class="col-md-10">  
  48.                 @Html.TextBoxFor(m => m.Country, new { @class = "form-control" })  
  49.                 @Html.ValidationMessageFor(model => model.Country, nullnew { @class = "text-danger" })  
  50.             </div>  
  51.         </div>  
  52.         <div class="form-group">  
  53.             <div class="col-md-offset-2 col-md-10">  
  54.                 <input type="submit" class="btn btn-default" value="Register" />  
  55.             </div>  
  56.         </div>  
  57.     </div>  
  58. }  
  59.   
  60. @section Scripts {  
  61.     @Scripts.Render("~/bundles/jqueryval")  
  62. }   
Now, just put a breakpoint and check the execution.



Now, it will check; if the entered country is present in allowcountry by splitting the string, if not; then it will return an error message.



Here, Controller code is given below.
  1. // POST: /Account/Register  
  2.        [HttpPost]  
  3.        [AllowAnonymous]  
  4.        [ValidateAntiForgeryToken]  
  5.        public async Task<ActionResult> Register(RegisterViewModel model)  
  6.        {  
  7.            if (ModelState.IsValid)  
  8.            {  
  9.                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };  
  10.                var result = await UserManager.CreateAsync(user, model.Password);  
  11.                if (result.Succeeded)  
  12.                {  
  13.                    await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);  
  14.                      
  15.   
  16.   
  17.                    return RedirectToAction("Index""Home");  
  18.                }  
  19.                AddErrors(result);  
  20.            }  
  21.   
  22.            // If we got this far, something failed, redisplay form  
  23.            return View(model);  
  24.        }  
Here, the output is produced.


In this way, we can create our own validation attributes and can use in the project.

Now, check this functionality in Web API 2.0.

Create a MVC WebAPI project.

Add the model given below.
  1. public class Register  
  2.   {  
  3.       [Required]  
  4.       [EmailAddress]  
  5.       [Display(Name = "Email")]  
  6.       public string Email { getset; }  
  7.       public string FirstName { getset; }  
  8.       [Required(ErrorMessage = "Last Name is Required")]  
  9.       public string LastName { getset; }  
  10.   
  11.       public string Country { getset; }  
  12.   
  13.   
  14.   
  15.   }  
Now, add a class to create your own validation, as shown below.
  1. public sealed class checkCountry : ValidationAttribute  
  2.    {  
  3.        public String AllowCountry { getset; }  
  4.   
  5.        protected override ValidationResult IsValid(object country, ValidationContext validationContext)  
  6.        {  
  7.            string[] myarr = AllowCountry.ToString().Split(',');  
  8.            if (myarr.Contains(country))  
  9.            {  
  10.                return ValidationResult.Success;  
  11.            }  
  12.            else  
  13.            {  
  14.                return new ValidationResult("Please choose a valid country eg.(India,Pakistan,Nepal)");  
  15.            }  
  16.        }  
  17.   
  18.    }  
 

Now, add the attribute in the model.
  1. public class Register  
  2.    {  
  3.        [Required]  
  4.        [EmailAddress]  
  5.        [Display(Name = "Email")]  
  6.        public string Email { getset; }  
  7.        public string FirstName { getset; }  
  8.        [Required(ErrorMessage = "Last Name is Required")]  
  9.        public string LastName { getset; }  
  10.   
  11.        [checkCountry(AllowCountry = "India,Pakistan,Nepal", ErrorMessage = "please enter a valid country eg( India,SriLanka,Nepal.)")]  
  12.        public string Country { getset; }  
  13.   
  14.   
  15.   
  16.    }  
Now, Register Controller is shown.



The actual code for Controller action method is given.
  1. [Route("Register")]  
  2.        public async Task<HttpResponseMessage> RegisterUser(Register obj)  
  3.        {  
  4.            Dictionary<stringobject> dict = new Dictionary<stringobject>();  
  5.   
  6.            if (!ModelState.IsValid)  
  7.            {  
  8.                string errordetails = "";  
  9.                var errors = new List<string>();  
  10.                foreach (var state in ModelState)  
  11.                {  
  12.                    foreach (var error in state.Value.Errors)  
  13.                    {  
  14.                        string p = error.ErrorMessage;  
  15.                        errordetails = errordetails + error.ErrorMessage;  
  16.   
  17.                    }  
  18.                }  
  19.       
  20.                dict.Add("error", errordetails);  
  21.                return Request.CreateResponse(HttpStatusCode.BadRequest, dict);  
  22.   
  23.            }  
  24.            else  
  25.            {  
  26.                dict.Add("Success""Register successfully");  
  27.                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK,dict);  
  28.                return response;  
  29.            }  
  30.   
  31.        }  
Now, check the Register method, using PostMan client.

Lets put an invalid country and test first.



Now, put the valid data and test the result.

 
Thus, in this way, we can create our validation attribute and use it in both MVC and WebAPI.