Catch me catch me if you can - Errors on MVC
There are so many articles about the various ways to handle errors that you probably don't need another one. I am just going to focus on some key points and some gotchas!
The 404 Error
(Page or Route not found -
is not as much an error as an exception and it is handled differently)
This is why we typically reference a special page for 404 errors in our config
<customErrors mode="On" defaultRedirect="error" >
<error statusCode="404" redirect="~/error/error_notfound"/>
</customErrors>
Make sure in your App_Start FilterConfig file that you are adding the filter for HandleErrorAttribute
filters.Add(new HandleErrorAttribute());
I have implemented a custom Error handler as well so I have a filter included for that file
filters.Add(new CustomErrorHandling());
public class CustomErrorHandling : HandleErrorAttribute, IExceptionFilter
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
{
return;
}
if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
{
return;
}
// if the request is AJAX return JSON else view.
if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = filterContext.Exception.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
};
// ExceptionUtility.NotifyWebTeam(filterContext.Exception);
}
My default redirect goes to "error" - So rather than depend on the Home Controller I added an Error Controller and am landing on the default page with some generic code as shown:
<h3 class="text-danger">Error.</h3>
<h4 class="text-danger">An error occurred while processing your request.</h4>
Controller: @Model.ControllerName<br />
Action:@Model.ActionName.ToString()<br /><br />
@if (Model.Exception.InnerException != null)
{
@Model.Exception.InnerException.StackTrace;
@Request.IsLocal;
@Model.Exception.InnerException.Message;
}
Message: @Model.Exception.Message<br />
@if (Model.Exception.Message != null && Model.Exception.Message.ToString().Contains("A potentially dangerous Request.Form"))
{
@:Our system does not accomodate HTML. Please use the browsers back button to review your entries and try again.
}
else
{
@:Our web team has been notified of this issue.
}
}
}
}
The 404 Error
(Page or Route not found -
is not as much an error as an exception and it is handled differently)
This is why we typically reference a special page for 404 errors in our config
<customErrors mode="On" defaultRedirect="error" >
<error statusCode="404" redirect="~/error/error_notfound"/>
</customErrors>
Make sure in your App_Start FilterConfig file that you are adding the filter for HandleErrorAttribute
filters.Add(new HandleErrorAttribute());
I have implemented a custom Error handler as well so I have a filter included for that file
filters.Add(new CustomErrorHandling());
public class CustomErrorHandling : HandleErrorAttribute, IExceptionFilter
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
{
return;
}
if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
{
return;
}
// if the request is AJAX return JSON else view.
if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = filterContext.Exception.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
};
// ExceptionUtility.NotifyWebTeam(filterContext.Exception);
}
My default redirect goes to "error" - So rather than depend on the Home Controller I added an Error Controller and am landing on the default page with some generic code as shown:
<h3 class="text-danger">Error.</h3>
<h4 class="text-danger">An error occurred while processing your request.</h4>
Controller: @Model.ControllerName<br />
Action:@Model.ActionName.ToString()<br /><br />
@if (Model.Exception.InnerException != null)
{
@Model.Exception.InnerException.StackTrace;
@Request.IsLocal;
@Model.Exception.InnerException.Message;
}
Message: @Model.Exception.Message<br />
@if (Model.Exception.Message != null && Model.Exception.Message.ToString().Contains("A potentially dangerous Request.Form"))
{
@:Our system does not accomodate HTML. Please use the browsers back button to review your entries and try again.
}
else
{
@:Our web team has been notified of this issue.
}
}
}
}
Comments