Monday 16 March 2015

Exception Handling in MVC

No matter how proficiently you developed your application there are chances that your code may not work as expected and will generate an error at runtime. Users may enter some invalid data, mathematical calculations can go wrong, some network level fault may cause errors and more. That is why it is always a good idea to implement a robust error handling mechanism in your web application. To that end ASP.NET MVC offers several techniques that help you build such an error handling mechanism. This article discusses them with examples.

Exception Handling Techniques for ASP.NET MVC

Before we get into the actual error handling techniques offered by ASP.NET MVC, let's quickly enumerate them here:
  • try...catch
  • Overriding OnException method
  • Using the [HandleError] attribute on actions and controllers
  • Handling Application_Error event (Global Error Handling in Mvc)

Using the Try...Catch Statement
The simplestwayis to use the traditional .NET exception handling style i.e. try and catch block. Now when exception happens catch block gets executed and it redirects to the error view.

        public ActionResult SomeError()
        {
            try
            {
                return View();
            }
            catch (Exception ex)
            { return View("Error"); }
        }

Error.cshtml :

@model System.Web.Mvc.HandleErrorInfo

@{
    ViewBag.Title = "Error";
}

<hgroup class="title">
    <h1 class="error">Error.</h1>
    <h2 class="error">An error occurred while processing your request.</h2>
</hgroup>

Limitation:
Problem with the above approach is we cannot reuse the exception handling logic across multiple action methods.

Overriding OnException Method
In this method we can override the “OnException” event of the controller and set the “Result” to the view name. This view gets invoked when error occurs in this controller. In the below code you can see we have set the “Result” to a view named as “Error”.
We have also set the exception so that it can be displayed inside the view.

protected override void OnException(ExceptionContext filterContext)
        {
            Exception ex = filterContext.Exception;
            filterContext.ExceptionHandled = true;

            var model = new HandleErrorInfo(filterContext.Exception, "Controller", "Action");

            filterContext.Result = new ViewResult()
            {
                ViewName = "Error",
                ViewData = new ViewDataDictionary(model)
            };

        }

To display the above error in view we can use the below code in Index.cshtml file:-

@Model.Exception;

Advantage
Now we can share error handling logic across all the actions in a controller

Limitation:
Problem with the above approach is we cannot reuse the exception handling logic across multiple controllers. That where global error handling comes to picture.

Using HandleError Attribute

The other way of handling error is my using “HandleError” attribute. Implementing “HandleError” attribute is a two-step process:-
Step 1 :- We need to first decorate the action method with “HandleError” attribute as shown in the below code.
    public class HomeController : Controller
        {
            [HandleError()]
            public ActionResult SomeError()
            {
                throw new Exception("test");
            }
        }
Step 2:- In the “Web.config” file you need to add the “customErrors” tag and point to the “Error” view as shown in the below “Web.config” code snippet.

<system.web>
<customErrors defaultRedirect="Error.cshtml" mode="On">
</customErrors>
</system.web>

In case you want different error views for different exception types you can decorate action method with multiple “HandleError” attribute point to multiple views as per exception types.
   public class HomeController : Controller
        {
            [HandleError(ExceptionType = typeof(ArithmeticException), View = "Arthimetic")]
            [HandleError(ExceptionType = typeof(NotImplementedException), View = "Error1")]
            public ActionResult SomeError()
            {

            }
        }

Global Error Handling in Mvc

The last exception handling technique discussed here is the Application_Error event. If you ever worked with ASP.NET Web Forms chances are you already know about this event. The Application_Error event is raised whenever  there is any unhandled exception in the application. That means an exception is not handled by any of the other techniques discussed earlier, it eventually gets bubbled up to the Application_Error event. Inside this event handler you can do tasks such as error logging and take some alternate path of execution. The following code shows how Application_Error can be added to Global.asax:

       protected void Application_Error()
        {
            Server.ClearError();
            Response.Redirect("/home/error");
        }

The Application_Error event handler calls Server.ClearError() so as to convey to ASP.NET that the exception has been handled and that there is no longer an exception in the application. This way if you have set a custom error page in the web.config, it won't be displayed. Then the code redirects the user to /home/error so that the Error view is displayed in the browser.

Summary

Error handling is an important consideration in any web application. ASP.NET MVC offers several error handling techniques in addition to try...catch that you can use. They include - overriding OnException() method, [HandleError] attribute, HandleErrorAttribute as a global filter and Application_Error event. Which of these techniques to use depends on the granularity of exception handling you need in an application.

0 comments:

Post a Comment

Topics

ADFS (1) ADO .Net (1) Ajax (1) Angular (43) Angular Js (15) ASP .Net (14) Authentication (4) Azure (3) Breeze.js (1) C# (47) CD (1) CI (2) CloudComputing (2) Coding (7) CQRS (1) CSS (2) Design_Pattern (6) DevOps (4) DI (3) Dotnet (8) DotnetCore (16) Entity Framework (2) ExpressJS (4) Html (4) IIS (1) Javascript (17) Jquery (8) Lamda (3) Linq (11) microservice (3) Mongodb (1) MVC (46) NodeJS (8) React (11) SDLC (1) Sql Server (32) SSIS (3) SSO (1) TypeScript (1) UI (1) UnitTest (1) WCF (14) Web Api (15) Web Service (1) XMl (1)

Dotnet Guru Archives