Custom Exception Filter In ASP.NET MVC

In this article, I am going to discuss Custom Exception Filters in MVC with one real-time example.

Introduction

There are some limitations to the Exception Filter.

  1. The error won’t get logged anywhere.
  2. Exceptions raised outside controllers will not be handled. Example- exception raised because of invalid URL won’t be handled.
  3. Exception Handling based on the scenario is not possible. Example – So one error page when the request comes via AJAX and a different one when comes via normal request.

We will overcome all these problems by creating a Custom Exception Filter in MVC that means we will create a Custom Handle Error Filter in MVC application.

Step 1

Create a database table in SQL Server 2014 or a version of your choice.

Employee Table

  1. CREATE TABLE [dbo].[Employee](  
  2.     [Id] [int] IDENTITY(1,1) NOT NULL,  
  3.     [Name] [nvarchar](50) NULL,  
  4.     [Gender] [char](10) NULL,  
  5.     [Age] [intNULL,  
  6.     [Position] [nvarchar](50) NULL,  
  7.     [Office] [nvarchar](50) NULL,  
  8.     [Salary] [intNULL,  
  9.  CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED   
  10. (  
  11.     [Id] ASC  
  12. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  13. ON [PRIMARY]  
  14.   
  15. GO  

ExceptionLogger Table

  1. CREATE TABLE [dbo].[ExceptionLogger](  
  2.     [ExceptionId] [int] IDENTITY(1,1) NOT NULL,  
  3.     [ExceptionMessage] [nvarchar](maxNULL,  
  4.     [ControllerName] [nvarchar](100) NULL,  
  5.     [ActionName] [nvarchar](100) NULL,  
  6.     [ExceptionStackTrack] [nvarchar](maxNULL,  
  7.     [ExceptionLogTime] [datetime] NULL,  
  8.  CONSTRAINT [PK_ExceptionLogger] PRIMARY KEY CLUSTERED   
  9. (  
  10.     [ExceptionId] ASC  
  11. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  12. ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]  
  13.   
  14. GO  

Step 2

Open Visual Studio 2015 or an editor of your choice and create a new project.

Step 3

Choose the web application project and give an appropriate name to your project.
 
Custom Exception Filter In ASP.NET MVC 

Step 4

Select empty template, check on MVC checkbox below, and click OK.
 
Custom Exception Filter In ASP.NET MVC 

Step 5

Right-click on the Models folder and add a database model. Add Entity Framework now. For that, right-click on Models folder, select Add, then select "New Item".
 
Custom Exception Filter In ASP.NET MVC 

You will get a window; from there, select Data from the left panel and choose ADO.NET Entity Data Model. Give the name as EmployeeModel (this name is not mandatory, you can give any name) and click "Add".

Custom Exception Filter In ASP.NET MVC 

After you click on "Add a window", the wizard will open. Choose EF Designer from the database and click "Next".

Custom Exception Filter In ASP.NET MVC 

After clicking on "Next", a window will appear. Choose New Connection. Another window will appear. Add your server name - if it is local, then enter a dot (.). Choose your database and click "OK".

Custom Exception Filter In ASP.NET MVC 

The connection will be added. If you wish, save the connection name as you want. You can change the name of your connection below. It will save the connection in the web config. Now, click "Next"

Custom Exception Filter In ASP.NET MVC 

After clicking on NEXT, another window will appear. Choose the database table name as shown in the below screenshot and click "Finish".

Custom Exception Filter In ASP.NET MVC 

Entity Framework gets added and the respective class gets generated under the Models folder.

Custom Exception Filter In ASP.NET MVC 

Employee Class

  1. using System.ComponentModel.DataAnnotations;  
  2.    
  3. namespace MvcCustomExceptionFilter.Models  
  4. {  
  5.     using System;  
  6.     using System.Collections.Generic;  
  7.       
  8.     public partial class Employee  
  9.     {  
  10.         public int Id { getset; }  
  11.    
  12.         [Required(ErrorMessage = "Please enter name")]  
  13.         public string Name { getset; }  
  14.    
  15.         [Required(ErrorMessage = "Please choose gender")]  
  16.         public string Gender { getset; }  
  17.    
  18.         [Required(ErrorMessage = "Please enter age")]  
  19.         public Nullable<int> Age { getset; }  
  20.    
  21.         [Required(ErrorMessage = "Please enter position")]  
  22.         public string Position { getset; }  
  23.    
  24.         [Required(ErrorMessage = "Please enter you office location")]  
  25.         public string Office { getset; }  
  26.    
  27.         [Required(ErrorMessage = "Please enter your salary")]  
  28.         public Nullable<int> Salary { getset; }  
  29.     }  
  30. }  

Step 6

Right click on controllers folder and add controller.
 
Custom Exception Filter In ASP.NET MVC 

A window will appear. Choose MVC5 Controller-Empty and click "Add".

Custom Exception Filter In ASP.NET MVC 

After clicking on "Add", another window will appear with DefaultController. Change the name to HomeController and click "Add". The HomeController will be added under the Controllers folder. Don’t change the Controller suffix for all controllers, change only the highlight, and instead of Default, just change Home;

Custom Exception Filter In ASP.NET MVC 

Complete code for Home Controller

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using MvcCustomExceptionFilter.CustomFilter;  
  7. using MvcCustomExceptionFilter.Models;  
  8.    
  9. namespace MvcCustomExceptionFilter.Controllers  
  10. {  
  11.     public class HomeController : Controller  
  12.     {  
  13.         private readonly EmployeeContext _dbContext=new EmployeeContext();  
  14.    
  15.         public ActionResult Index()  
  16.         {  
  17.             var employee = _dbContext.Employees.ToList();  
  18.             return View(employee);  
  19.         }  
  20.    
  21.         public ActionResult Create()  
  22.         {  
  23.             return View();  
  24.         }  
  25.    
  26.         [HttpPost]  
  27.         [CustomExceptionHandlerFilter]  
  28.         public ActionResult Create(Employee employee)  
  29.         {  
  30.             if (ModelState.IsValid)  
  31.             {  
  32.                 if (employee.Position == "Software Engineer" && (employee.Salary < 50000 || employee.Salary > 80000))  
  33.                 {  
  34.                     throw new Exception("Salary is not matching with Software Engineer position.");  
  35.                 }  
  36.                 else if (employee.Position == "Accountant" && (employee.Salary < 40000 || employee.Salary > 50000))  
  37.                 {  
  38.                     throw new Exception("Salary is not matching with Accountant position.");  
  39.                 }  
  40.                 else if (employee.Position == "Senior Sales Executive")  
  41.                 {  
  42.                     throw new Exception("Salary is not matching with Senior Sales Executive position.");  
  43.                 }  
  44.                 else  
  45.                 {  
  46.                     _dbContext.Employees.Add(employee);  
  47.                     _dbContext.SaveChanges();  
  48.                 }  
  49.             }  
  50.             return RedirectToAction("Index");  
  51.         }  
  52.     }  
  53. }  

Step 7

Right click on Index method in HomeController The "Add View" window will appear with default index name checked (use a Layout page), and click on "Add.
 
Custom Exception Filter In ASP.NET MVC 

Code for Index View

  1. @model IEnumerable<MvcCustomExceptionFilter.Models.Employee>  
  2.    
  3. @{  
  4.     ViewBag.Title = "Index";  
  5. }   
  6.    
  7. @Html.ActionLink("Add New","Create","Home",new {@class="btn btn-primary",style="margin-top:10px; margin-bottom:10px;"})  
  8.    
  9. <table class="table table-bordered">  
  10.     <thead>  
  11.     <tr>  
  12.         <th>@Html.DisplayNameFor(m=>m.Name)</th>  
  13.         <th>@Html.DisplayNameFor(m=>m.Gender)</th>  
  14.         <th>@Html.DisplayNameFor(m=>m.Age)</th>  
  15.         <th>@Html.DisplayNameFor(m=>m.Position)</th>  
  16.         <th>@Html.DisplayNameFor(m=>m.Office)</th>  
  17.         <th>@Html.DisplayNameFor(m=>m.Salary)</th>  
  18.     </tr>  
  19.     </thead>  
  20.     @foreach (var emp in Model)  
  21.     {  
  22.         <tr>  
  23.             <td>@emp.Name</td>  
  24.             <td>@emp.Gender</td>  
  25.             <td>@emp.Age</td>  
  26.             <td>@emp.Position</td>  
  27.             <td>@emp.Office</td>  
  28.             <td>@emp.Salary</td>  
  29.         </tr>  
  30.     }  
  31. </table>  

Code for Creating view

  1. @model MvcCustomExceptionFilter.Models.Employee  
  2. @{  
  3.     ViewBag.Title = "Create";  
  4. }  
  5.    
  6. <h2>Create</h2>  
  7.    
  8. @using (Html.BeginForm())  
  9. {  
  10.     <div class="form-group">  
  11.         @Html.LabelFor(m => m.Name)  
  12.         @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })  
  13.         @Html.ValidationMessageFor(m => m.Name)  
  14.     </div>  
  15.     <div class="form-group">  
  16.         @Html.LabelFor(m => m.Name)  
  17.         @Html.DropDownList("Gender",new List<SelectListItem>()  
  18.         {  
  19.             new SelectListItem {Text = "Male",Value = "1"},  
  20.             new SelectListItem {Text = "Female", Value = "2"}  
  21.         },new {@class="form-control"})  
  22.    
  23.         @Html.ValidationMessageFor(m => m.Gender)  
  24.     </div>  
  25.     <div class="form-group">  
  26.         @Html.LabelFor(m => m.Age)  
  27.         @Html.TextBoxFor(m => m.Age, new { @class = "form-control" })  
  28.         @Html.ValidationMessageFor(m => m.Age)  
  29.     </div>  
  30.     <div class="form-group">  
  31.         @Html.LabelFor(m => m.Position)  
  32.         @Html.TextBoxFor(m => m.Position, new { @class = "form-control" })  
  33.         @Html.ValidationMessageFor(m => m.Position)  
  34.     </div>  
  35.     <div class="form-group">  
  36.         @Html.LabelFor(m => m.Office)  
  37.         @Html.TextBoxFor(m => m.Office, new { @class = "form-control" })  
  38.         @Html.ValidationMessageFor(m => m.Office)  
  39.     </div>  
  40.     <div class="form-group">  
  41.         @Html.LabelFor(m => m.Salary)  
  42.         @Html.TextBoxFor(m => m.Salary, new { @class = "form-control" })  
  43.         @Html.ValidationMessageFor(m => m.Salary)  
  44.     </div>  
  45.     <div class="form-group">  
  46.         <button type="submit" class="btn btn-primary">Submit</button>  
  47.     </div>  
  48. }  

Step 8

Right click on project create a folder CustomFilter add a class with name CustomExceptionHandlerFilter.cs,
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using MvcCustomExceptionFilter.Models;  
  7.    
  8. namespace MvcCustomExceptionFilter.CustomFilter  
  9. {  
  10.     public class CustomExceptionHandlerFilter:FilterAttribute,IExceptionFilter  
  11.     {  
  12.         public void OnException(ExceptionContext filterContext)  
  13.         {  
  14.            ExceptionLogger logger=new ExceptionLogger()  
  15.            {  
  16.                ExceptionMessage = filterContext.Exception.Message,  
  17.                ExceptionStackTrack = filterContext.Exception.StackTrace,  
  18.                ControllerName = filterContext.RouteData.Values["controller"].ToString(),  
  19.                ActionName = filterContext.RouteData.Values["action"].ToString(),  
  20.                ExceptionLogTime = DateTime.Now  
  21.            };  
  22.            EmployeeContext dbContext=new EmployeeContext();  
  23.            dbContext.ExceptionLoggers.Add(logger);  
  24.            dbContext.SaveChanges();  
  25.    
  26.            filterContext.ExceptionHandled = true;  
  27.            filterContext.Result=new ViewResult()  
  28.            {  
  29.                ViewName = "Error"  
  30.            };  
  31.         }  
  32.     }  
  33. }  

Step 9

Create an error view under shared folder.
  1. @{  
  2.     ViewBag.Title = "Error";  
  3. }  
  4.    
  5. <hgroup>  
  6.     <h1>Error Occured </h1>  
  7.     <h1 class="alert alert-danger">An unknown error occurred while processing your request.</h1>         
  8. </hgroup>  

Step 10

Enable custom errors in the web.config file that is present in the root directory of MVC application. customErrors element must be nested under <system.web>.
  1. <customErrors mode="On"></customErrors>  

Step 11

Create a class FilterConfig under App_Start folder if don’t have.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using Microsoft.ApplicationInsights.DataContracts;  
  7. using MvcCustomExceptionFilter.CustomFilter;  
  8.    
  9. namespace MvcCustomExceptionFilter.App_Start  
  10. {  
  11.     public class FilterConfig  
  12.     {  
  13.         public static void RegisterGlobalFilter(GlobalFilterCollection filters)  
  14.         {  
  15.             filters.Add(new CustomExceptionHandlerFilter());  
  16.         }  
  17.     }  
  18. }  

Step 12

Now, register your custom exception filter in Global.asax.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using System.Web.Routing;  
  7. using MvcCustomExceptionFilter.App_Start;  
  8.    
  9. namespace MvcCustomExceptionFilter  
  10. {  
  11.     public class MvcApplication : System.Web.HttpApplication  
  12.     {  
  13.         protected void Application_Start()  
  14.         {  
  15.             FilterConfig.RegisterGlobalFilter(GlobalFilters.Filters);  
  16.             AreaRegistration.RegisterAllAreas();  
  17.             RouteConfig.RegisterRoutes(RouteTable.Routes);  
  18.         }  
  19.     }  
  20. }  

Step 13

Build and run you project ctrl+F5.
 
Custom Exception Filter In ASP.NET MVC 
Custom Exception Filter In ASP.NET MVC
Custom Exception Filter In ASP.NET MVC