Exception Filter in ASP.NET Core MVC

Exception Filter in ASP.NET Core MVC

In this article, I will discuss the Exception Filter in ASP.NET Core MVC Application with Examples. Please read our previous article discussing the basic concepts of Filters in ASP.NET Core MVC Applications. As part of this article, we will discuss the following pointers in detail.

  1. What is an Exception Filter in ASP.NET Core MVC?
  2. Built-in Exception Filter in ASP.NET Core MVC
  3. Example to understand UseExceptionHandler Middleware
  4. How Do We Create a Custom Exception Filter in ASP.NET Core MVC?
  5. Differences Between Exception Handler and Exception Filter in ASP.NET Core.
What is an Exception Filter in ASP.NET Core MVC?

In ASP.NET Core MVC, Exception Filter allows us to handle unhandled exceptions that occur while processing an HTTP request within our application. Exception Filters in ASP.NET Core Applications are used for tasks such as Logging Exceptions, Returning Custom Error Responses, and Performing any other necessary action when an exception occurs.

Exception Filter also provides a way to centralize the exception-handling logic and keep it separate from our controller or from the business and data access logic, making our code more organized and maintainable.

Built-In Exception Filter in ASP.NET Core MVC

The ASP.NET Core Framework does not provide any specialized Built-in Exception Filter for Global Error Handling. As developers, we generally use the UseExceptionHandler middleware component to handle exceptions globally.

However, we can also create a Custom Exception Filter to handle unhandled exceptions globally. In ASP.NET Core, we can create the Custom Exception Filter in two ways: First, we can create a class implementing the IExceptionFilter interface and provide implementations for the [OnException] method. Second, by creating a class inherited from the ExceptionFilterAttribute class and overriding the [OnException] method.

Example to understand UseExceptionHandler Middleware in ASP.NET Core

Let us first see an example of how the UseExceptionHandler middleware component handles unhandled exceptions globally. Then, we will see how to create a Custom Exception Filter.

The UseExceptionHandler Middleware allows us to specify an error-handling path that will be executed when an unhandled exception is thrown within our application. We can configure this using the Main method of our Program class.

To configure UseExceptionHandler middleware for global Exception Handling, please add the following code to the program class. With the following code in place, if an exception occurs and if the environment is not Development, then the user will be redirected to the “/Home/Error” URL. Here, Home is the Controller name, and Error is the action method within the Home Controller. If the environment is Development, it will display the complete error details using the UseDeveloperExceptionPage middleware component.

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    // This will handle exceptions and redirect to the specified error page.
    app.UseExceptionHandler("/Home/Error");
}
Modify the Home Controller:

Next, modify the Home Controller as follows. As you can see in the code below, within the Index action method, we have written the logic in a way that it will throw runtime exceptions while executing it. Further, if you notice, we have not handled that exception within the Index action method. Again, we have added the Error action method, which should be executed when there is an unhandled exception and if the environment is not set to be Development.

using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            int x = 10;
            int y = 0;
            int z = x / y;

            return View();
        }

        public ActionResult Error()
        {
            return View();
        }
    }
}

Next, add the Error.cshtml view of the Home Controller. Once you add the Error view, copy and paste the following code. The following view will be executed when your application has an unhandled exception.

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1 style="color:red">Unknwo Error</h1>
        <h2 style="color:red">An unknown error has occurred. We are working on it. Please try after some time</h2>
    </hgroup>
</body>
</html>

Now, set the environment to Production or Staging and run the application, and you should see the following generic error message.

Exception Filter in ASP.NET Core MVC

How Do We Create a Custom Exception Filter in ASP.NET Core MVC?

As we already discussed, we can create the Custom Exception Filter in two ways: First, we can create a class implementing the IExceptionFilter interface and provide implementations for the [OnException] method. Second, we can create a class inherited from the ExceptionFilterAttribute class and override the [OnException] method.

Let us see an example of creating a custom exception filter that logs the exception details. The following are the steps to create and use a Custom Exception filter in ASP.NET Core MVC Application:

Create a Custom Exception Filter Class

So, create a class file named CustomExceptionFilter.cs and copy and paste the following code. The class inherits from the ExceptionFilterAttribute and overrides the OnException method, where we write our custom logic. In the code below, we fetch the Controller Name, Action Name, and Exception message from the Context object and then log the details into a text file.

using Microsoft.AspNetCore.Mvc.Filters;
namespace FiltersDemo.Models
{
    public class CustomExceptionFilter : ExceptionFilterAttribute
    {
        public override void OnException(ExceptionContext context)
        {
            var controllerName = context.RouteData.Values["controller"];
            var actionName = context.RouteData.Values["action"];
           
            string message = $"\nTime: {DateTime.Now}, Controller: {controllerName}, Action: {actionName}, Exception: {context.Exception.Message}";
            string filePath = Path.Combine(Directory.GetCurrentDirectory(), "Log", "Log.txt");
            //saving the data in a text file called Log.txt
            File.AppendAllText(filePath, message);
        }
    }
}
Applying the Custom Exception Filter:

We can apply the Custom Exception Filter at three levels: Globally, At the Action Method Level, and At the Controller Level. We have created the Custom Exception Filter inheriting from the ExceptionFilterAttribute, which means our Custom Exception Filter is also an Attribute. As it is an Attribute, we can directly apply it to the Controller or Action Methods. Let us modify the Home Controller as follows to apply the Custom Exception Filter on the Index Action method.

using FiltersDemo.Models;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        [CustomExceptionFilter]
        public ActionResult Index()
        {
            int x = 10;
            int y = 0;
            int z = x / y;

            return View();
        }
    }
}

Note: If you create the Custom Exception Filter by implementing the IExceptionFilter or IAsyncExceptionFilter interface, you cannot apply that filter directly to the Controllers or Action Methods. In that case, you need to use the Built-in TypeFilter vs ServiceFilter Attribute at the Controller and Action Methods to specify the Custom Filters. These two Built-in Filter Attributes are specifically designed for this purpose. In our upcoming articles, we will discuss the differences Between TypeFilter and ServiceFilter in ASP.NET Core MVC.

Registering the Filter Globally

We can also register the filter globally to apply to all actions in the application. This can be done in the Program.cs class file as follows:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new CustomExceptionFilter());
});
Creating Custom Exception Filter by Implementing IExceptionFilter Interface:

Let us see how we can implement the IExceptionFilter Interface and provide implementations for the OnException method to create a Custom Exception Filter. Let us modify the CustomExceptionFilter class as follows, which inherits from the IExceptionFilter Interface and implements the OnException method. As part of the OnException method, we have written our custom exception logic, which will log the unhandled exception details to a text file:

using Microsoft.AspNetCore.Mvc.Filters;
namespace FiltersDemo.Models
{
    public class CustomExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            var controllerName = context.RouteData.Values["controller"];
            var actionName = context.RouteData.Values["action"];
           
            string message = $"\nTime: {DateTime.Now}, Controller: {controllerName}, Action: {actionName}, Exception: {context.Exception.Message}";
            string filePath = Path.Combine(Directory.GetCurrentDirectory(), "Log", "Log.txt");
            //saving the data in a text file called Log.txt
            File.AppendAllText(filePath, message);
        }
    }
}

Note: You need to remember that the above CustomExceptionFilter class is no longer an Attribute. Hence, we cannot apply this CustomExceptionFilter as an Attribute in our Controller or Action Method.

Register the Custom Exception Filter Globally

You can register the custom exception filter globally in the Program.cs file as follows. This is for Global registration:

// Global registration
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new CustomExceptionFilter());
});
OR
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(typeof(CustomExceptionFilter));
});

You can apply the custom exception filter to specific controllers or actions using ServiceFilter or TypeFilter attributes. So, modify the Home Controller as follows:

using FiltersDemo.Models;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        [ServiceFilter(typeof(CustomExceptionFilter))]
        public ActionResult Index()
        {
            int x = 10;
            int y = 0;
            int z = x / y;

            return View();
        }
    }
}

So, by following these steps, we can create and apply a Custom Exception Filter in our ASP.NET Core MVC Application. 

Redirecting to an Error View

Let’s see an example of how the Exception Filter redirects the user to a Custom Error view when an unhandled exception occurs while processing the request. This is similar to the example we created with the UseExceptionHandler middleware component. Let’s create the error view within the Views/Shared folder named Error.cshtml and then copy and paste the following code.

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1 style="color:red">Unknwon Error</h1>
        <h2 style="color:red">An unknown error has occurred. We are working on it. Please try after some time</h2>
    </hgroup>
</body>
</html>
Creating the Custom Exception Filter Attribute:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace FiltersDemo.Models
{
    public class RedirectToErrorViewFilter : ExceptionFilterAttribute
    {
        public override void OnException(ExceptionContext context)
        {
            context.Result = new ViewResult
            {
                ViewName = "Error"
            };
            context.ExceptionHandled = true;
        }
    }
}

Next, modify the Home Controller as follows:

using FiltersDemo.Models;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        [RedirectToErrorViewFilter]
        public ActionResult Index()
        {
            // Simulate an authorization exception
            throw new UnauthorizedAccessException("Access Denied.");
        }
    }
}
When Should We Use Exception Filter in ASP.NET Core MVC?

The Custom Exception filters are useful in the following scenarios:

  • Centralized Exception Handling: If you want a single, centralized location to handle all the unhandled exceptions that occur throughout your application, exception filters are a good choice. 
  • Error Logging: Exception filters provide a convenient mechanism for logging exceptions or collecting error information. You can log exceptions to various targets (e.g., files, databases, or external services).
  • Custom Error Responses: Exception filters are helpful when you need to customize the HTTP response sent to the client in case of an exception. You can set specific HTTP status codes, return custom error messages, and format responses according to your application’s requirements.

Difference Between Exception Handler and Exception Filter in ASP.NET Core

In ASP.NET Core, Exception Handlers (UseExceptionHandler) and Exception Filters (Custom Exception Filters) handle unhandled exceptions that occur during application execution. Let us proceed and understand the differences between them:

Exception Handler in ASP.NET Core

The Exception Handler in ASP.NET Core is used to catch unhandled exceptions that occur during the processing of HTTP requests in the middleware pipeline. It catches exceptions globally for the entire application. The following are the key points of the Exception Handler.

  • Typically configured in the Program.cs file.
  • Use app.UseExceptionHandler to configure a global exception handler.
  • It is useful for catching exceptions that occur in the middleware before the execution reaches the MVC action methods.
  • A typical use case is configuring a centralized error handling page or error logging middleware.
  • It is often used to return generic error responses in production to hide sensitive error information from end-users.
Exception Filter in ASP.NET Core

The Exception Filters in ASP.NET Core apply custom error-handling logic to handle unhandled exceptions thrown by controller action methods. The following are the key points of the Exception Filter.

  • It is implemented as part of the MVC pipeline.
  • It can be applied globally, per-controller or per-action, using attributes.
  • It is useful for handling exceptions specific to controller actions, such as customizing the response based on the type of exception thrown by an action.
  • A common use case is to catch domain-specific exceptions in a controller and return a specific HTTP status code or view.
  • It is often used to transform the exception into a custom error view or a JSON response.
Key Differences Between Exception Handler and Exception Filter in ASP.NET Core
  • Context of Operation: Exception handlers work at the middleware level and handle global exceptions across the entire application. Exception filters are part of the MVC filter pipeline and handle the exceptions thrown by controller actions.
  • Configuration: Exception handlers are configured in the middleware pipeline, usually in the Program.cs file. Exception filters are configured in the MVC pipeline and can be applied using attributes.

In the next article, I will discuss Handling Non-Success HTTP Status Codes in ASP.NET Core MVC Applications. In this article, I try to explain the Exception Filter in ASP.NET Core MVC Application with Examples. I hope you understand the need and use of the Exception Filter in ASP.NET Core MVC applications.

Leave a Reply

Your email address will not be published. Required fields are marked *