Back to: ASP.NET Core Tutorials For Beginners and Professionals
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.
- What is an Exception Filter in ASP.NET Core MVC?
- Built-in Exception Filter in ASP.NET Core MVC
- Example to understand UseExceptionHandler Middleware
- How to Create Custom Exception Filter in ASP.NET Core MVC?
- What is ServiceFilter Attribute in ASP.NET Core MVC?
- Real-Time Examples of Custom Exception Filter in ASP.NET Core MVC
- When to Use Exception Filter in ASP.NET Core MVC?
- 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, an Exception Filter is a filter that allows us to handle unhandled exceptions that occur while processing an HTTP request within our application. Exception Filters are part of the ASP.NET Core MVC framework and perform actions when unhandled exceptions are thrown while executing controller action methods or middleware components.
Exception Filters in ASP.NET Core Applications are typically used for tasks such as Logging Exceptions, Returning Custom Error Responses, and Performing any other necessary action when an exception occurs. They provide a way to centralize the exception-handling logic and keep it separate from our controller or middleware components, making our code more organized and maintainable.
Built-In Exception Filter in ASP.NET Core MVC
The ASP.NET Core Framework provides no specialized Built-in Exception Filter for Global Error Handling. Instead, developers commonly use middleware components such as UseExceptionHandler for global exception handling.
However, we can create a Custom Exception Filter. We can create the Custom Exception Filter in two ways: First, by creating a class implementing the IExceptionFilter interface and providing implementations for the [OnException] method. Second, by creating a class inheriting from the ExceptionFilterAttribute class and overriding the [OnException] method.
Example to understand UseExceptionHandler Middleware in ASP.NET Core
The UseExceptionHandler Middleware is widely used for global exception handling in ASP.NET Core applications. It 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 within the Main method of our Program class.
To Configure UseExceptionHandler Middleware for Global Exception Handling, please add the following code within the Program class. With this code in place, if an exception occurs and if the environment is not Development, then the user will be redirected to “/Home/Error“. Here, Home is the Controller name, and Error is the action method within the Home Controller.
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 below code, within the Index action method, we have written the logic in such a way that it will throw runtime exceptions while executing the Index action method, and 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.
How to Create Custom Exception Filter in ASP.NET Core MVC?
Creating a Custom Exception filter in ASP.NET Core MVC involves defining a class that inherits from ExceptionFilterAttribute or implements the IExceptionFilter or IAsyncExceptionFilter interface. The following are the steps to create and use a Custom Exception filter in ASP.NET Core MVC Application:
Step 1: Create a Custom Exception Filter Class
In ASP.NET Core MVC, we can create the Custom Exception Filter in two ways: First, by creating a custom class implementing the IExceptionFilter interface and providing implementations for the OnException method. Second, by creating a custom class inheriting from the ExceptionFilterAttribute class and overriding the OnException method. Let us see an example of creating a custom exception filter that logs the exception details:
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 have written our custom logic.
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 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.
Example for Handling Unauthorized Access (AuthorizationException)
In this example, we will create an Exception Filter to handle authorization failures (e.g., when a user is not authorized to access a resource). We will return a 403 Forbidden status code with a custom error message.
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace FiltersDemo.Models { public class AuthorizationExceptionFilter : ExceptionFilterAttribute { public override void OnException(ExceptionContext context) { if (context.Exception is UnauthorizedAccessException) { // Return a 403 Forbidden response context.Result = new ObjectResult("Access denied.") { StatusCode = 403, }; // Mark the exception as handled context.ExceptionHandled = true; } } } }
Now, we can apply the AuthorizationExceptionFilter to our controller actions or globally. For example, we can apply it to a specific action that requires authorization:
using FiltersDemo.Models; using Microsoft.AspNetCore.Mvc; namespace FiltersDemo.Controllers { public class HomeController : Controller { [AuthorizationExceptionFilter] public ActionResult Index() { // Simulate an authorization exception throw new UnauthorizedAccessException("Access Denied."); } } }
When you access the /home/index URL without proper authorization, the AuthorizationExceptionFilter will handle the exception and return a 403 Forbidden response.
Redirecting to an Error View
Let us see an example of how the Exception Filter Redirects the user to a custom error view. Let us create the error view within the Home folder with the name Error.cshtml with the following HTML 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."); } } }
Real-Time Examples of Exception Filter in ASP.NET Core MVC:
Let’s explore real-world examples of how exception filters can improve the error-handling experience.
Example for Handling Database Exceptions
Imagine you have an ASP.NET Core MVC application that interacts with a database. You want to handle database-related exceptions and provide informative error messages to users. In this example, the DatabaseExceptionFilter is used to catch SqlException instances, which can occur when there’s a database-related issue. It logs the exception and returns a user-friendly error message with a 500 Internal Server Error status code.
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Data.SqlClient; namespace FiltersDemo.Models { public class DatabaseExceptionFilter : ExceptionFilterAttribute { public override void OnException(ExceptionContext context) { if (context.Exception is SqlException sqlException) { //Log the error details into a log file // Return a user-friendly error response context.Result = new ObjectResult("A database error occurred. Please try again later.") { StatusCode = 500, }; // Mark the exception as handled context.ExceptionHandled = true; } } } }
Example for Handling API Exceptions
Suppose you build an API using ASP.NET Core and want to provide consistent error responses for API clients when exceptions occur. In this example, the ApiExceptionFilter is designed for handling exceptions in API actions. It logs the exception, creates a structured JSON error response, and returns it with a 500 Internal Server Error status code.
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using System.Net; namespace FiltersDemo.Models { public class ApiExceptionFilter : ExceptionFilterAttribute { public override void OnException(ExceptionContext context) { //Log the Exception // Create an error response with a meaningful JSON structure var errorResponse = new { StatusCode = (int)HttpStatusCode.InternalServerError, Message = "An error occurred while processing your request.", Details = context.Exception.Message }; // Return the error response as a JSON result context.Result = new ObjectResult(errorResponse) { StatusCode = (int)HttpStatusCode.InternalServerError, }; // Mark the exception as handled context.ExceptionHandled = true; } } }
When to Use Exception Filter in ASP.NET Core MVC?
Choosing when to use an Exception Filter in ASP.NET Core MVC should be a decision based on your application’s specific needs and complexities. You should consider using Exception Filters in ASP.NET Core MVC when you want to centralize and customize handling unhandled exceptions while processing HTTP requests. Exception filters are useful in the following scenarios:
- Centralized Exception Handling: If you want a single, centralized location to handle exceptions that occur throughout your application, exception filters are a good choice. They allow you to define consistent error-handling logic for different parts of your application.
- Logging and Error Reporting: 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) and generate detailed error reports for monitoring, debugging, and troubleshooting.
- 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.
- Reusability: If you have common exception-handling patterns repeated in multiple controller actions or middleware components, you can encapsulate this logic in a reusable exception filter. This promotes code reuse and reduces duplication of error-handling code.
- Exception Transformation: Exception Filters allow us to transform exceptions into more user-friendly or application-specific error messages. You can catch low-level exceptions and present them to users in a more user-friendly format.
- Global Exception Handling: When you want to apply exception handling globally across all controller actions or a subset of actions, exception filters can be registered globally in the Startup.cs class or Program.cs class. This ensures consistent error handling without applying attributes to individual actions.
- Security and Validation: Exception filters can also be used for security-related tasks, such as handling authorization errors or validating input data. For example, you can create an exception filter to handle authorization failures and return appropriate responses to unauthorized requests.
Difference Between Exception Handler and Exception Filter in ASP.NET Core
In ASP.NET Core, exception handlers and exception filters are used to manage exceptions, but they serve different purposes and are used in different contexts. Understanding their differences is important for effective error handling in your application.
Exception Handler in ASP.NET Core
Purpose: Exception handlers are used to catch unhandled exceptions that occur during the processing of HTTP requests in the middleware pipeline.
Scope: They catch exceptions globally for the entire application or specific middleware components.
Usage:
- Typically configured in the Startup.cs or 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.
- Example: A typical use case is configuring a centralized error handling page or error logging middleware.
Customization:
- You can redirect to a specific error page or return a custom response.
- Often used to return generic error responses in production to hide sensitive error information from end-users.
Exception Filter in ASP.NET Core
Purpose: Exception filters are used to apply custom error handling logic or transformations to exceptions thrown by action methods or action result execution in MVC controllers.
Scope: They operate within the context of the MVC action methods.
Usage:
- Implemented as part of the MVC filter pipeline.
- It can be applied globally, per-controller, or per-action using attributes.
- Useful for handling exceptions that are specific to controller actions, such as customizing the response based on the type of exception thrown by an action.
- Example: A common use case is to catch domain-specific exceptions in a controller and return a specific HTTP status code or view.
Customization:
- Allows for more granular control over the handling of exceptions.
- It can be used to transform the exception into a specific action result, like returning 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 are used for global exception handling across the entire application. Exception filters are part of the MVC filter pipeline and provide more fine-grained control over exceptions thrown by controller actions.
- Configuration: Exception handlers are configured in the middleware pipeline, usually in the Startup.cs or Program.cs file. Exception filters are configured in the MVC pipeline and can be applied using attributes.
- Flexibility and Control: Exception filters offer more flexibility and control, allowing for specific responses based on the exception type or the context of the controller action.
While exception handlers and exception filters are used for error handling in ASP.NET Core, they differ in scope, level of control, and configuration. Exception handlers are suitable for global error-handling strategies, whereas exception filters provide a more detailed and context-specific approach within the MVC framework.
In the next article, I will discuss Handling Non-Success HTTP Status Codes in ASP.NET Core MVC Applications. Here, 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 Exception Filters in ASP.NET Core MVC applications.
About the Author: Pranaya Rout
Pranaya Rout has published more than 3,000 articles in his 11-year career. Pranaya Rout has very good experience with Microsoft Technologies, Including C#, VB, ASP.NET MVC, ASP.NET Web API, EF, EF Core, ADO.NET, LINQ, SQL Server, MYSQL, Oracle, ASP.NET Core, Cloud Computing, Microservices, Design Patterns and still learning new technologies.