I have an MVC 4 app, using a custom HandleErrorAttribute to handle only custom exceptions. I would like to intercept the default 404 and other non-500 error pages and replace them with something more attractive. To that end, I added the following to my Web.config:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error/Index" />
...
</ system.web>
I have an Error controller with an Index method and corresponding view, but still I get the default 404 error page. I have also tried setting my defaultRedirect
to a static html file to no avail. I have tried adding error handling specific to 404's inside <customErrors>
, and I even tried modifying the routes programattically, all with no results. What am I missing? Why is ASP ignoring my default error handling?
Note: I noticed earlier that I cannot test my CustomHandleErrorAttribute locally, even with <customErrors mode="On"
. It does work when I hit it on my server from my dev box though... not sure if that is related. This guy had the same problem.
This should work :
1. Web.Config
<customErrors mode="On"
defaultRedirect="~/Views/Shared/Error.cshtml">
<error statusCode="403"
redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
<error statusCode="404"
redirect="~/Views/Shared/FileNotFound.cshtml" />
</customErrors>
2. Registered HandleErrorAttribute as a global action filter in the FilterConfig class as follows
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
filters.Add(new AuthorizeAttribute());
}
If that dont work then, Try to make yourself transfer the response by checking status codes like the Following in the Global.asax: at least it must work.
void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode == 401)
{
Response.ClearContent();
Server.Transfer("~/Views/Shared/UnauthorizedAccess.cshtml");
}
}
I am going little off topic. I thought this is bit important to explain.
If you pay attention to the above highlighted part. I have specified the order of the Action Filter. This basically describes the order of execution of Action Filter. This is a situation when you have multiple Action Filters implemented over Controller/Action Method
This picture just indicates that let's say you have two Action Filters. OnActionExecution
will start to execute on Priority and OnActionExecuted
will start from bottom to Top. That means in case of OnActionExecuted
Action Filter having highest order will execute first and in case of OnActionExecuting
Action Filter having lowest order will execute first. Example below.
public class Filter1 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Execution will start here - 1
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Execution will move here - 5
base.OnActionExecuted(filterContext);
}
}
public class Filter2 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Execution will move here - 2
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Execution will move here - 4
base.OnActionExecuted(filterContext);
}
}
[HandleError]
public class HomeController : Controller
{
[Filter1(Order = 1)]
[Filter2(Order = 2)]
public ActionResult Index()
{
//Execution will move here - 3
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
}
You may already aware that there are different types of filters within MVC framework. They are listed below.
Authorization filters
Action filters
Response/Result filters
Exception filters
Within each filter, you can specify the Order property. This basically describes the order of execution of the Action Filters.
This works for me. This is very easy and no need to consider any change in Web.Config or Register the Action Filter in Global.asax file.
ok. So, First I am creating a simple Action Filter. This will handle Ajax and Non Ajax requests.
public class MyCustomErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
var debugModeMsg = filterContext.HttpContext.IsDebuggingEnabled
? filterContext.Exception.Message +
"\n" +
filterContext.Exception.StackTrace
: "Your error message";
//This is the case when you need to handle Ajax requests
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = debugModeMsg
}
};
}
//This is the case when you handle Non Ajax request
else
{
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Error";
routeData.DataTokens["area"] = "app";
routeData.Values["exception"] = debugModeMsg;
IController errorsController = new ErrorController();
var exception = HttpContext.Current.Server.GetLastError();
var httpException = exception as HttpException;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (System.Web.HttpContext.Current.Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
var rc = new RequestContext
(
new HttpContextWrapper(HttpContext.Current),
routeData
);
errorsController.Execute(rc);
}
base.OnException(filterContext);
}
}
Now you can implement this Action Filter on Controller as well as on the Action only.Example:
Hope this should help you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With