Monday, May 16, 2016

Exception handling in ASP.NET MVC

ASP.NET MVC 4

By default in asp.net MVC the exceptions are handled by the controller if you enable the customErrors in web.config. The error.cshtml in shared folder is called when ever there is an exception in actionMethod.

<system.web>
    <customErrors mode="On">
    </customErrors>
</system.web>

However if you need custom errors of you choice, then you need to use the HandleError attribute.


 [HandleError( View = "PageNotFound")]



In the below snippet, the result due to 1/0, raises the arthimetic exception then calls the ArthimeticExeView by the HandleError attribute

Code Snippet:
HomeController:

[HandleError(ExceptionType = typeof(ArithmeticException), View = "ArthimeticExeView")]
        public ActionResult TestHandleError()
        {
            var a = 1;
            var b = 0;
            var result = a / b;
            return View();
        }


ArthimeticExeView.cshtml:


<h1>Attempted to divide by zero.</h1>





The above method has a drawback of re-usability. Because it has a view name(ArthimeticExeView) that contains the message for arithmetic exception In order to keep a common view for all exceptions, then we need to pass the exception message using the custom error handling attribute. 

In CustomErrHandler we override the onException method and returns the exception message to view model.

Code Snippet:
HomeController:

             [CustomErrHandler]
        public ActionResult TestHandleError2()
        {
            var a = 1;
            var b = 0;
            var result = a / b;
            return View();
        }



CustomErrHandler.cs:


    public class CustomErrHandler : HandleErrorAttribute
    {
        public 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 = "Error1",
                ViewData = new ViewDataDictionary(model)
            };
        }
    }


Error1.cshtml:


@model System.Web.Mvc.HandleErrorInfo

@{
    ViewBag.Title = "Error";
}

<h1>@ViewData.Model.Exception.Message</h1>



In MVC the views that are not called by the specific controller ActionMethod

Below are the ways, the views are not called by the controller actionMethod.

Method 1: Having the common folder called shared. Views in shared folder donot require a controller actionMethod. When ever an action method executes and returns a view that is not located in its path. Then it will check the shared folder by that view name.

Ex: return view("NoData")

Here the NoData is searched in shared folder if is not located in the views folder corresponding to that controller.

Method 2: If there are 100 views with some static data, then does it make sense in creating 100 actionMethods in controller. Obviously no, in such a case, the MVC framework helps us with the method HandleUnknownAction that executes whenever an attempt to invoke the action method that doesnot exist.


        protected override void HandleUnknownAction(string actionName)
        {
            try
            {
                this.View(actionName).ExecuteResult(this.ControllerContext);
            }
            catch(Exception ex)
            {
                Response.Redirect("PageNotFound");
            }
        }

Code Snippet:
    public class HomeController : Controller
    {
        protected override void HandleUnknownAction(string                                                                  actionName)
        {
            try
            {                                           this.View(actionName).ExecuteResult(this.ControllerContext);

            }
            catch(Exception ex)
            {
                Response.Redirect("PageNotFound");
            }
        }

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

    }