Introduction
In this example we will create a custom attribute that will validate the customer email id and mobile number uniqueness while inserting a new customer in the database. There are the following Customer table scripts that we will work on in this article.
- CREATE TABLE [dbo].[tblEmployee](
- [EmployeeId] [int] IDENTITY(1,1) NOT NULL,
- [Name] [nvarchar](50) NOT NULL,
- [Gender] [nvarchar](10) NULL,
- [City] [nvarchar](50) NOT NULL,
- [EmailId] [nvarchar](50) NOT NULL,
- [MobileNo] [nvarchar](15) NOT NULL,
- PRIMARY KEY CLUSTERED
- (
- [EmployeeId] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
I am inserting the following sample data:
- INSERT INTO [manishDB].[dbo].[tblEmployee]
- ([Name]
- ,[Gender]
- ,[City]
- ,[EmailId]
- ,[MobileNo])
- VALUES
- ('Manish'
- ,' Male'
- ,'Hyderabad'
- ,'[email protected]'
- ,'9052390048')
- GO
- INSERT INTO [manishDB].[dbo].[tblEmployee]
- ([Name]
- ,[Gender]
- ,[City]
- ,[EmailId]
- ,[MobileNo])
- VALUES
- ('Venkat'
- ,‘Male'
- ,'Hyderabad'
- ,'[email protected]'
- ,'9452390048')
Use the following procedure and create a remote custom attribute in MVC.
Step 1
Now open Visual Studio and go to "File" -> "New" -> "Project..." and under the web tab select ASP.NET web application and provide a meaningful name. In this case I am giving “CustomRemoteAttributeDemo” and click on the Ok button.
Step 2
Select MVC from the template tab and click on OK.
Step 3
By default a MVC 5 project with some default code appears in Solution Explorer. Delete that if you want or leave it as it is. Now go to the Models folder and right-click on that then select add and select ADO.NET Entity Data Model and provide a meaningful name say EmployeeDb and click Ok.
Step 4
Select "EF Designer from database" in the Entity Data Model Wizard then click "Next". Create a connection string and provide a meaningful name such as “EmployeeDbContext” and click "Next".
Step 5
Select the tblEmployee table and in Namespace write the Models as namespace and click on "Finish".
Step 6
Now our tblEmployee entity is ready. Change the name to Employee and build the project once so that all the code compiles correctly.
Step 7
Now go to the controller folder and right-click on it and select Add then select New Scaffolded Items as follows.
Step 8
The following dialog box appears. Select "MVC5 controller with views using Entity Framework" and click "Add".
Step 9
Then for "Model Class" select Employee and for the "Data context class" select "EmployeeDbContext" and leave the rest as defaults and click on "Add".
Note: Remote attribute only works when JavaScript is enabled. If the end user disables JavaScript on his/her machine then the validation does not work. This is because RemoteAttribute requires JavaScript to make an asynchronous AJAX call to the server-side validation method. As a result, the user will be able to submit the form, bypassing the validation in place. This's why it is always important to have server-side validation.
Step 10
By default the controller and related view has been generated by MVC. Run the project and navigate to create the action method. Here if we insert the same mobile number and email id then it is also accepting that we need to remove by creating a custom attributes. The custom attribute will be used in the entire project so it will be best if we place it in a separate folder called common. Create a common folder and one class says “CustomRemoteAttribute”(you can give it a meaningful name) inside that folder.
For creating a remote attributes in MVC we need to inherit the RemoteAttribute class with it available inside the using System.Web.Mvc; namespace. So do this first like:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace CustomRemoteAttributeDemo.Common
- {
- public class CustomRemoteAttribute : RemoteAttribute
- {
-
- }
- }
Step 11
Then we need to override the IsValid function of class RemoteAttribute. The best way to override any function is to just type the override keyword then you will find the list of all the functions that can be overriden.
In this case we need to override the IsValide method that accepts two parameters. Just click on that and you will get the following code and delete that return code and implement the logic there.
- protected override System.ComponentModel.DataAnnotations.ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext)
- {
- return base.IsValid(value, validationContext);
- }
Step 12
Then we need to write some reflection code so first add the namespace "using System.Reflection;" and start writing the following code inside the IsValide() methord.
-
- Type controller = Assembly.GetExecutingAssembly().GetTypes()
- .FirstOrDefault(type => type.Name.ToLower() == string.Format("{0}Controller",
- this.RouteData["controller"].ToString()).ToLower());
Step 13
Then check to ensure the controller is available. If the controller is available then find the method that will check the database with a mobile number or email id and return true or false as a JOSN result. Here in this case create the following two methods to determine email id and mobile number availability. Create both methods inside the Employees controller.
- public JsonResult IsMobileNumberAvailable(string MobileNumber)
- {
- return Json(!db.Employees.Any(x => x.MobileNo == MobileNumber),
- JsonRequestBehavior.AllowGet);
- }
- public JsonResult IsEmailIdAvailable(string EmailId)
- {
- return Json(!db.Employees.Any(x => x.EmailId == EmailId),
- JsonRequestBehavior.AllowGet);
- }
Step 14
Now go to IsValide() inside the common folder and write the following code.
Code
- protected override ValidationResult IsValid(object value, ValidationContext validationContext)
- {
-
-
- Type controller = Assembly.GetExecutingAssembly().GetTypes()
- .FirstOrDefault(type => type.Name.ToLower() == string.Format("{0}Controller",
- this.RouteData["controller"].ToString()).ToLower());
- if (controller != null)
- {
-
- MethodInfo action = controller.GetMethods()
- .FirstOrDefault(method => method.Name.ToLower() ==
- this.RouteData["action"].ToString().ToLower());
- if (action != null)
- {
-
- object instance = Activator.CreateInstance(controller);
-
- object response = action.Invoke(instance, new object[] { value });
- if (response is JsonResult)
- {
- object jsonData = ((JsonResult)response).Data;
- if (jsonData is bool)
- {
- return (bool)jsonData ? ValidationResult.Success :
- new ValidationResult(this.ErrorMessage);
- }
- }
- }
- }
- return new ValidationResult(base.ErrorMessageString);
- }
Step 15
Now create the following constructor to set the error message and access the server-side and client-side response.
- public CustomRemoteAttribute(string routeName)
- : base(routeName)
- {
- }
-
- public CustomRemoteAttribute(string action, string controller)
- : base(action, controller)
- {
- }
-
- public CustomRemoteAttribute(string action, string controller,
- string areaName) : base(action, controller, areaName)
- {
- }
Step 16
Build the project and now we need to apply DataAnnotations validation to an employee table, For that create a class EmployeeMetadata and apply the validation like the following.
- [MetadataType(typeof(EmployeeMetadata))]
- public partial class Employee
- {
-
- }
- public class EmployeeMetadata
- {
- [CustomRemoteAttribute("IsEmailIdAvailable", "Employees",
- ErrorMessage = "Email Id already in use")]
- public string EmailId { get; set; }
- [CustomRemoteAttribute("IsMobileNumberAvailable", "Employees",
- ErrorMessage = "Mobile Number already in use")]
- public string MobileNo { get; set; }
- }
Here we need to add the reference "using CustomRemoteAttributeDemo.Common;" if your project name and class name are different then add that class reference.
That's it. Run the project and navigate to create a view and try to insert the duplicate email id then you will get the following error.
Summary
In this illustration you came to understand how to create custom remote attributes in MVC. Download the sample code for a better understanding. Thanks. I would like to get feedback from my readers. Please post your feedback, question, or comments about this article.