Check If Username/Email Already Registered Using Remote Validation Attribute in ASP.NET MVC

When we create Registration form on a web application, we have to check that the email address and username that user is entering is unique and is not already taken by another user. In ASP.NET MVC we have Validation Attribute feature under System.ComponentModel.DataAnnotations and System.Web.Mvc which we can use for different type of Validations before sending data to be saved in persistent location.

In System.Web.Mvc we have Remote attribute which is available in ASP.NET MVC 4 in which I am implementing it for this post. I am not sure if it is available in the earlier version of ASP.NET MVC.

So I have this ViewModel:

  1. public class SignUpViewModel  
  2. {  
  3.   
  4.     public int UserID   
  5.   {  
  6.         get;  
  7.         set;  
  8.     }  
  9.   
  10.     [Required(ErrorMessage = "First Name is required")]  
  11.     public string FirstName  
  12.     {  
  13.         get;  
  14.         set;  
  15.     }  
  16.   
  17.     [Required(ErrorMessage = "Last Name is Required")]  
  18.     public string LastName  
  19.     {  
  20.         get;  
  21.         set;  
  22.     }  
  23.   
  24.     [Required(ErrorMessage = "Username is Required")]  
  25.     [RegularExpression(@ "^[a-zA-Z0-9]+$", ErrorMessage = "user name must be combination of letters and numbers only.")]  
  26.     public string UserName  
  27.     {  
  28.         get;  
  29.         set;  
  30.     }  
  31.   
  32.     [Required(ErrorMessage = "Password is Required")]  
  33.     public string Password   
  34.     {  
  35.         get;  
  36.         set;  
  37.     }  
  38.   
  39.     [Required(ErrorMessage = "Password is Required")]  
  40.     [System.Web.Mvc.Compare("Password", ErrorMessage = "Both Password fields must match.")]  
  41.     public string ConfirmPassword   
  42.     {  
  43.         get;  
  44.         set;  
  45.     }  
  46.   
  47.     [Required(ErrorMessage = "Email Address is required")]  
  48.     [EmailAddress(ErrorMessage = "Invalid Email Address")]  
  49.     public string Email   
  50.     {  
  51.         get;  
  52.         set;  
  53.     }  
As you can see there are already attributes on the properties of ViewModel like Required which are mandatory fields, RegularExpression attribute for Email Address format validation and Compare attribute for comparing two properties values which is useful here for Password and Repeat Password textbox for making sure that user has verified what password he is setting.

Now what will happen if user enters a username or Email Address which is already registered, one way is to check in post action for username and Email Address and show user error message that username or Email Address has already taken which does not look though, as validation should be done before posting data to action using unobtrusive validation.

Now here we will use Remote attribute which will check for both UserName and Email Address field, here is how it will be done:
  1. [Required(ErrorMessage = "Username is Required")]  
  2. [RegularExpression(@ "^[a-zA-Z0-9]+$", ErrorMessage = "user name must be combination of letters and numbers only.")]  
  3. [Remote("UsernameExists""Account", HttpMethod = "POST", ErrorMessage = "User name already registered.")]  
  4. public string UserName  
  5. {  
  6.     get;  
  7.     set;  
  8. }  
  9.   
  10. [Required(ErrorMessage = "Email Address is required")]  
  11. [EmailAddress(ErrorMessage = "Invalid Email Address")]  
  12. [Remote("EmailExists""Account", HttpMethod = "POST", ErrorMessage = "Email address already registered.")]  
  13. public string Email  
  14. {  
  15.     get;  
  16.     set;  
  17. }  
Remote Attribute has different parameters to be specified: 
  1. Action Name which will be called which will have input parameter for this property value.
  2. Controller Name of which action will be executed.
  3. HttpMethod (Get or Post).
  4. ErrorMessage (Error Message that will be displayed if validation fails).

Let's come to the action part we need to write action method in the Account controller for Validation, for this post just for readers understanding I am just checking specific username and email (my name and dummy email address), but in your project you will need to check in your database for that particular criteria and return true or false respectively.

Here is the action code:

  1. public JsonResult UsernameExists(string username)   
  2. {  
  3.     return Json(!String.Equals(username, "ehsansajjad", StringComparison.OrdinalIgnoreCase));  
  4. }  
  5.   
  6. public JsonResult EmailExists(string email)  
  7. {  
  8.     return Json(!String.Equals(email, "ehsansajjad@yahoo.com", StringComparison.OrdinalIgnoreCase));  
  9. }  
Here is the complete View code
  1. @model CustomValidationMessageHelper.ViewModels.SignUpViewModel  
  2. @{  
  3.     Layout = null;  
  4. }  
  5.   
  6. <!DOCTYPE html>  
  7.   
  8. <html>  
  9. <head>  
  10.     <meta name="viewport" content="width=device-width" />  
  11.     <title>SignUp</title>  
  12.     <link href="@Url.Content("~/Content/jquery.qtip.css")" rel="stylesheet" />  
  13.   
  14.     <script src="@Url.Content("~/Scripts/jquery-1.9.1.js")"></script>  
  15.     <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script>  
  16.     <script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>  
  17.     <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>  
  18.     <script src="@Url.Content("~/Scripts/jquery.qtip.min.js")" type="text/javascript"></script>  
  19.   
  20. </head>  
  21. <body>  
  22.     <div>  
  23.         @using (Html.BeginForm("SignUp""Account", FormMethod.Post, new { @class = "form-inline", role = "form" }))  
  24.         {  
  25.           @Html.AntiForgeryToken()  
  26.       
  27.     <div class="row">  
  28.         <div class="span8 offset5 aui-page-panel">  
  29.   
  30.             <div>  
  31.                     <h2>Sign Up</h2>  
  32.                 </div>  
  33.             <fieldset style="margin-bottom: 40px;">  
  34.                   
  35.   
  36.                                 <legend style="border-bottom: 1px solid gray; font-size: 16px;">Basic Information</legend>  
  37.   
  38.                 <table width="100%" border="0" cellspacing="0" cellpadding="0">  
  39.                     <tr id="tr_basic">  
  40.                         <td style="vertical-align: top;" width>  
  41.                             <div id="basicinfo" style="width: 100%">  
  42.                                 <div style="height: auto !important; overflow-y: visible;">  
  43.                                     <table cellpadding="3">  
  44.   
  45.                                         <tbody>  
  46.                                             <tr>  
  47.                                                 <td width="150">  
  48.                                                     @Html.LabelFor(model => model.FirstName, new { @class = "sr-only" })  
  49.                                                 </td>  
  50.                                                 <td>  
  51.                                                     @Html.TextBoxFor(model => model.FirstName, new { @class = "form-control input-sm" })  
  52.                                                     @Html.ValidationMessageFor(model => model.FirstName)  
  53.                                                 </td>  
  54.   
  55.                                             </tr>  
  56.                                             <tr>  
  57.                                                 <td>  
  58.                                                     @Html.LabelFor(model => model.LastName)  
  59.                                                 </td>  
  60.                                                 <td>  
  61.                                                     @Html.TextBoxFor(model => model.LastName, new { @class = "input-xsmall" })  
  62.                                                     @Html.ValidationMessageFor(model => model.LastName)  
  63.                                                 </td>  
  64.                                             </tr>  
  65.   
  66.                                               
  67.                                             <tr>  
  68.                                             </tr>  
  69.   
  70.                                         </tbody>  
  71.                                     </table>  
  72.   
  73.                                 </div>  
  74.                         </td>  
  75.                     </tr>  
  76.   
  77.                 </table>  
  78.   
  79.   
  80.                 <legend style="border-bottom: 1px solid gray; font-size: 16px;">Account Information</legend>  
  81.                 <table cellpadding="5">  
  82.                     <tr>  
  83.                         <td width="150">  
  84.                             @Html.LabelFor(model => model.UserName)  
  85.                         </td>  
  86.                         <td>  
  87.                             @Html.TextBoxFor(model => model.UserName)  
  88.                             @Html.ValidationMessageFor(model => model.UserName)  
  89.                         </td>  
  90.                         <td id="tdValidate">  
  91.                             <img id="imgValidating" src="@Url.Content("~/Images/validating.gif")" style="display:none;" /></td>  
  92.   
  93.                     </tr>  
  94.                     <tr>  
  95.                         <td>  
  96.                             @Html.LabelFor(model => model.Password)  
  97.                         </td>  
  98.                         <td>  
  99.                             @Html.PasswordFor(model => model.Password)  
  100.                             @Html.ValidationMessageFor(model => model.Password)  
  101.   
  102.   
  103.                         </td>  
  104.   
  105.                     </tr>  
  106.   
  107.   
  108.                     <tr>  
  109.                         <td>  
  110.                             @Html.LabelFor(m => m.ConfirmPassword, new { @class = "control-label" })  
  111.                         </td>  
  112.   
  113.                         <td>  
  114.                             @Html.PasswordFor(model => model.ConfirmPassword)  
  115.                             @Html.ValidationMessageFor(model => model.ConfirmPassword)  
  116.   
  117.                         </td>  
  118.                     </tr>  
  119.                     <tr>  
  120.                         <td>  
  121.                             @Html.LabelFor(m => m.Email, new { @class = "control-label" })  
  122.                         </td>  
  123.   
  124.                         <td>  
  125.                             @Html.TextBoxFor(model => model.Email)  
  126.                             @Html.ValidationMessageFor(model => model.Email)  
  127.   
  128.   
  129.                         </td>  
  130.   
  131.                     </tr>  
  132.                     <tr>  
  133.                     <td>  
  134.                         <p>  
  135.                             <div class="control-group">  
  136.                                 <div class="controls">  
  137.                                     <input id="btnRegister" type="submit" class="btn btn-primary" value="Register" />  
  138.                                 </div>  
  139.                             </div>  
  140.   
  141.                         </p>  
  142.                     </td>  
  143.                     <td></td>  
  144.                 </tr>  
  145.                 </table>  
  146.     </div>  
  147.      </div>  
  148.             }  
  149.             </div>  
  150.           
  151. </body>  
  152. </html>  
Now when I will enter username "ehsansajjad" or Email Address "ehsansajjad@yahoo.com" validation will get fired that user already exists:

signup

You can download the sample project here.