Exception Handling in MVC

Exception handling is the process of responding to the occurrence of exceptional conditions requiring special processing. Exception handling is important in any application. In ASP.NET we can handle exceptions in the following two ways.

  • Try-catch-finally block at method level
  • Using Application_Error

Exception Handling in MVC

In ASP.NET MVC we have a larger list of ways to handle exceptions such as,

  • Try-catch-finally
  • Overriding OnException method
  • Using the [HandleError] attribute on actions and controllers
  • Setting a global exception-handling filter
  • Handling Application_Error event
  • Extending HandleErrorAttribute

To begin with, create a new empty ASP.NET MVC application. Add a controller as "ExceptionTestingController". Add a view for Index. Add another view at "Views\Shared" as "Error. cshtml".

For testing purposes, we would cause some kind of exception.

try-catch-finally

Change the Index as in the following.

public ActionResult Index()
{
    int a = 1;
    int b = 0;
    int c = 0;
    try
    {
        c = a / b; // This line would cause an exception.
    }
    catch (Exception ex)
    {
        return View("Error");
    }
    finally
    {
        // Optional code to execute after try block (e.g., cleanup)
    }
    return View();
}

Here we are generating an exception at "c = a / b;" inside the try block. In the catch, we are returning a different view "Error". If you run the application you will get an Error page in the browser. In an actual project, we can also use the catch block to log the error information.

Overriding OnException method

For this, remove the try block from the preceding code. We need to overwrite OnException as in the following.

public ActionResult Index()
{
    int a = 1;
    int b = 0;
    int c = 0;
    c = a / b; // This line would cause an exception.
    return View();
}

protected override void OnException(ExceptionContext filterContext)
{
    string action = filterContext.RouteData.Values["action"].ToString();
    Exception e = filterContext.Exception;
    filterContext.ExceptionHandled = true;
    filterContext.Result = new ViewResult()
    {
        ViewName = "Error"
    };
}

OnException is a void method that takes an argument as an object of ExceptionContext that has all the information about the exception that can be used to log. We need to set ExceptionHandled = true for the ExceptionContext object. We can handle the exception generated from all the actions from a specific controller. We can get the action name from ExceptionContext as in.

string action = filterContext.RouteData.Values["action"].ToString();

There is a problem with this approach that we cannot reuse the exception handling logic across multiple controllers. That is where global error handling is useful.

Using HandleError Attribute

This is a simple way to handle exceptions in MVC. Remove the OnException implementation from the previous code. Use the following procedure to do that.

Step 1. Add <customErrors mode="On" ></customErrors> in web.config under <system.web>.

Step 2. Decorate the action with [HandleError] as,

[HandleError]
public ActionResult Index()
{
    int a = 1;
    int b = 0;
    int c = 0;
    c = a / b; // This line will cause an exception.
    return View();
}

We can handle a different exception with a different view with [HandleError] as in the following.

[HandleError]
[HandleError(ExceptionType = typeof(DivideByZeroException), View = "Error1")]
[HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "Error2")]
public ActionResult Index()
{
    int a = 1;
    int b = 0;
    int c = 0;
    c = a / b; // This would cause an exception.
    return View();
}

Here we should place a specific HandleError at the bottom if we reverse the order of the HandleError attribute then the Error. cshtml will always be displayed.

In the same way, we can decorate our controller with HandleError. This would handle the exception generated from all the actions from a specific controller.

Limitations

  • Does not support logging exceptions.
  • Doesn't catch HTTP exceptions other than 500.
  • Doesn't catch exceptions that are raised outside controllers.
  • Returns an error view even for exceptions raised in AJAX calls.

Setting a global exception-handling filter

For this, we need to ensure that HandleErrorAttribute is added in RegisterGlobalFilters of the FilterConfig file of App_start and registered in Application_Start. No need to decorate our action and controller with [HandleError].

Extending HandleErrorAttribute

We can also create our own Exception Handler by inheriting from HandleErrorAttribute as in the following.

public class MyExceptionHandler : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled || filterContext.HttpContext.IsCustomErrorEnabled)
        {
            return;
        }

        Exception e = filterContext.Exception;
        filterContext.ExceptionHandled = true;
        filterContext.Result = new ViewResult()
        {
            ViewName = "Error2"
        };
    }
}

We need to set ExceptionHandled = true for the ExceptionContext object. We can handle the exception generated from all the actions from a specific controller. We can also get the action name from ExceptionContext as in the following.

string action = filterContext.RouteData.Values["action"].ToString();

Now we can decorate our action/controller with [MyExceptionHandler] to use this.

[MyExceptionHandler]
public ActionResult Index()
{
    int a = 1;
    int b = 0;
    int c = 0;
    
    // This operation would cause an exception (division by zero).
    c = a / b;
    
    return View();
}


Similar Articles