Logging and catching exception in Asp.Net MVC using CustomHandleError filter

Exception loging for MVC Context using CustomErrorHandle Attribute.

 

Posted: May 13, 2017. | By: mustafa


How to handle custom error & exception in Asp.Net MVC code, this can be done in many ways by using try & catch block,Overriding the OnException method in the base Controller class. And also we can use HandleError attribute. Now we are going to extend HandleError filter to create CustomError handler.

Why do we need to extend HandleError filter?

  • With HandleErrorAttribute we get more control over exception handling. HandleError allow us to handle error differently for different controllers and actions easily.
  • Once we are into Application_Error we are out of MVC context and because of that we can miss some context information.

To handle custom error in Asp.Net MVC define CustomHandleErrorAttribute class inherited from HandleErrorAttribute and register custom handler with FilterConfig. HandleError is built-in filter CustomHandleError is extended to log the exceptions using NLog - nlog article, and return a JSON object for AJAX calls. If the request is an AJAX call then it will return a JSON object containing a boolean status and the custom message else will return the error view.

 public class CustomHandleErrorAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                // For AJAX requests, we're overriding the returned JSON result with a simple string,
                // indicating to the calling JavaScript code that a redirect should be performed.
                
                var controllerName = (string)filterContext.RouteData.Values["controller"];
                var actionName = (string)filterContext.RouteData.Values["action"];
                var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

                // Log for exception
                NLogger.LogWrite().Error(filterContext.Exception, filterContext.Exception.Message);

                filterContext.ExceptionHandled = true;
                filterContext.Result = new JsonResult
                {
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                    Data = new
                    {
                        CustomError = true,
                        CustomErrorMessage = "Custom error message"
                    }
                };
            }
            else
            {
                var controllerName = (string)filterContext.RouteData.Values["controller"];
                var actionName = (string)filterContext.RouteData.Values["action"];
                var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

                filterContext.Result = new ViewResult
                {
                    ViewName = View,
                    MasterName = Master,
                    ViewData = new ViewDataDictionary(model),
                    TempData = filterContext.Controller.TempData
                };

                // Log for exception
                NLogger.LogWrite().Error(filterContext.Exception, filterContext.Exception.Message);
                
                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.Clear();
                filterContext.HttpContext.Response.StatusCode = 500;
            }
        }
    }

 

Register CustomHandleErrorAttribute with global filter in FilterConfig.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new CustomHandleErrorAttribute());
        }

 

Create ErrorController add index method where we forcibly generate DivideByZeroException, redirecting to index view will give exception which is handled by CustomHandleErrorAttribute. Response is send to error view with exception details.

        public ActionResult Index()
        {
            int a = 0;
            int b = 5;
            int c = b / a;// divide by zero exception.
            return View();
        }
        public JsonResult TestException()
        {
            throw new ApplicationException();
            return Json(new { Valid = true });
        }

 

Error view defined in shared folder, we declared model HandleErrorInfo and getting all exception details like Exception type, message, stack trace, Response http code and error. Above exception details are shown when we HttpContext IsDebuggingEnabled is true or application is running in debug mode. On production server we can shown custom error message to user while we can log exception details on server.

@model System.Web.Mvc.HandleErrorInfo

@{
    ViewBag.Title = "Error";
}

<h2 class="text-danger">Error: @(!String.IsNullOrEmpty(Response.StatusCode.ToString()) ? Response.StatusCode.ToString() : "500 Error")</h2>
<h2 class="text-danger">@Response.StatusDescription</h2>

@if (Model != null && HttpContext.Current.IsDebuggingEnabled)
    {
    <div class="container">
        <div class="row">
            <div class="border-dash">
                <h4 class="heading">Controller Name</h4>
                <p>@Model.ControllerName</p>
            </div>
            <div class="border-dash">
                <h4 class="heading">Method Name</h4>
                <p>@Model.ActionName</p>
            </div>
            <div class="border-dash">
                <h4 class="heading">Exception Type</h4>
                <p>@Model.Exception.GetType()</p>
            </div>
            <div class="border-dash">
                <h4 class="heading">Exception Message</h4>
                <p>@Model.Exception.Message</p>
            </div>
            <div class="border-dash">
                <h4 class="heading">Exception Source</h4>
                <p>@Model.Exception.StackTrace</p>
            </div>
        </div>
    </div>
    }

 

At last, add ajax method calling TestException() above which will throw ApplicationException. Our CustomHandleErrorAttribute will check for ajax request and return jsonResult with custom error message to be shown to the user.

        $.ajax({
            url: "/Home/TestException",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            processdata: false,
            success: function (response) {
                if (response) {
                    callback(response);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                if (jqXHR != null) {
                    var responseText = $.parseJSON(jqXHR.responseText);
                    if (responseText.CustomError == true) {

                        alert(responseText.CustomErrorMessage);
                    }
                }
                else {
                    var response = { serviceError: true, jqXHR: jqXHR, textStatus: textStatus, errorThrown: errorThrown };
                    callback(response);
                }
            }
        });

 

When we visit the url ~/Error/Index we get the following error page.


CustomErrorPage.png, Exception Loging, Asp.Net, Exception,


related posts

Back to top