Custom Exception Filter in ASP.NET MVC

Custom Exception Filter in ASP.NET MVC Application

In this article, I am going to discuss Custom Exception Filter in ASP.NET MVC Application. Please read our previous article before proceeding to this article where we discussed the Exception Filter i.e. the built-in exception filter attribute HandleError. At the end of this article, you will understand what is the need for Custom Exception Filter and how to create and use Custom Exception Filter in ASP.NET MVC Application. We are going to work with the same example that we created in our previous article.

What is the need for Custom Exception Filter in ASP.NET MVC Application?

As we already discussed in our previous article, we cannot do the following things using the built-in HandleErrorr attribute

  1. We cannot log the Exception anywhere using the HandleError attribute.
  2. It is not possible to handle the exceptions raised outside the controllers.
  3. Scenario-based Exception Handling is not possible.

Let us see how to overcome the above problems by creating a Custom Exception Filter in MVC. Here in this article, I will show you how to log the exception in a text file but if you want then you can log the exception in the database too. Here our focus is on how to create the custom exception filter not how to log the exception.

Adding Log Folder:

Add a folder with the name Log into the project’s root directory. In this folder, we are going to log all the exceptions raised in our application using a text (i.e. Log.txt) file.

Creating Custom Exception Filter in MVC:

Here we need to create a class file by implementing the IExceptionFilter interface. So let’s have a look at the definition of the IExceptionFilter interface as shown below.

What is the need of Custom Exception Filter in ASP.NET MVC Application?

As you can see this interface belongs to System.Web.Mvc namespace and having only a single method declaration. The Custom Exception class that we are going to create is going to implement the above OnException method only. So, create a class file with the name LogCustomExceptionFilter.cs within the Models folder and then copy and paste the following code in it.

using System;
using System.IO;
using System.Web;
using System.Web.Mvc;

namespace ExceptionFilterInMVC.Models
{
    public class LogCustomExceptionFilter : FilterAttribute, IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            if (!filterContext.ExceptionHandled)
            {
                var exceptionMessage = filterContext.Exception.Message;
                var stackTrace = filterContext.Exception.StackTrace;
                var controllerName = filterContext.RouteData.Values["controller"].ToString();
                var actionName = filterContext.RouteData.Values["action"].ToString();
                
                string Message = "Date :" + DateTime.Now.ToString() + ", Controller: " + controllerName + ", Action:" + actionName +
                                 "Error Message : " + exceptionMessage
                                + Environment.NewLine + "Stack Trace : " + stackTrace;

                //saving the data in a text file called Log.txt
                //You can also save this in a dabase
                File.AppendAllText(HttpContext.Current.Server.MapPath("~/Log/Log.txt"), Message);
                
                filterContext.ExceptionHandled = true;
                filterContext.Result = new ViewResult()
                {
                    ViewName = "Error"
                };
            }
        }
    }
}

As you can see, the above class is derived from the FilterAttribute class. This is required as we want to use this class as a Filter attribute. This class is also implementing the IExceptionFilter interface and provides an implementation for OnException() method. This method contains the logic for storing the exception information in a text (i.e. .txt) file. First, it checks whether the exception has been handled or not by using the ExceptionHandled property. If the exception is not handled then it fetches the exception message (filterContext.Exception.Message), stack trace (filterContext.Exception.StackTrace), controller name (filterContext.RouteData.Values[“controller”].ToString()), and action method name (filterContext.RouteData.Values[“action”].ToString()) from the filterContext object. Then it stores the error info into the text file. Then it changes the ExceptionHandled property to true and redirects to the error page.

How to Register Custom Exception Filter in ASP.NET. MVC?

As a filter, you can use it at three different levels i.e. at the action level, at the Controller level, and globally. Let’s register this filter globally so that it will be applicable for all the action methods of all controllers of our application. To register it globally, open the FilterConfig class which is present in the App_Start folder, and then modify the class as shown below. If the FilterConfig class is not already present there then just create a class file with the name FilterConfig.cs within the App_Start folder.

FilterConfig.cs
using System.Web.Mvc;
using ExceptionFilterInMVC.Models;
namespace ExceptionFilterInMVC.App_Start
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new LogCustomExceptionFilter());
        }
    }
}

Note: While creating the project, if you have selected the Empty MVC Template then the above class (i.e. FilterConfig) will not present with you, but if you have selected any readymade MVC template then the above class will be available with your application. If this class file is not present then just create a class file with the name FilterConfig within the App_Start folder. This FilterConfig class is the centralized place where we used to add the Filters globally for our application. This will be instantiated when the Web application starts.

Modifying the Global.asax

As we know, the Application_Start() method of Global.asax file is the first method that is going to be executed when the application starts. So, from here we need to call the RegisterGlobalFilters() method of FilterConfig class so that all our filters that are registered globally will be instantiated at the time of application startup. So, modify the Application_Start() method of the Global.asax file as shown below.

using System.Web.Mvc;
using System.Web.Routing;
using ExceptionFilterInMVC.App_Start;
namespace ExceptionFilterInMVC
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            //calling RegisterGlobalFilters to register filters globally
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        }
    }
}
Modifying the Error.cshtml view:

Open the Error.cshtml file which is present inside the Shared folder which is inside the views folder. If Error.cshtml file is not present then just create it. Once you open the Error.cshtml file then copy and paste the following code in it.

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1>Unknwo Error</h1>
        <h2>An unknown error has occurred. We are working on it. Please try after some time</h2>
    </hgroup>
</body>
</html>
Modifying the HomeController:

Please modify the Home Controller as shown below to throw different types of exceptions from different action methods.

using System;
using System.Web.Mvc;
using ExceptionFilterInMVC.Models;

namespace ExceptionFilterInMVC.Controllers
{
    //[LogCustomExceptionFilter]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            throw new Exception("Something went wrong");
        }
        public ActionResult About()
        {
            throw new NullReferenceException();
        }
        public ActionResult Contact()
        {
            throw new DivideByZeroException();
        }
    }
}

That’s it. We are done with our implementation. Now, run the application and try to execute all the action methods, and then check the Log.txt file which should be created inside the Log folder.

In the next article, I am going to discuss how to display different error pages based on the different status codes in the ASP.NET MVC application. Here, in this article, I try to explain how to create and register Custom Exception Filter in ASP.NET MVC Application with a simple logging example. I hope you enjoy this Custom Exception Filter in MVC article.