Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC4 CustomErrors DefaultRedirect Ignored

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.

like image 562
therealmitchconnors Avatar asked Jul 14 '13 05:07

therealmitchconnors


2 Answers

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");
    }
}
like image 192
Nirmal Subedi Avatar answered Oct 20 '22 21:10

Nirmal Subedi


I am going little off topic. I thought this is bit important to explain.

enter image description here

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

enter image description here

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.

  1. Authorization filters

  2. Action filters

  3. Response/Result filters

  4. Exception filters

Within each filter, you can specify the Order property. This basically describes the order of execution of the Action Filters.

Back to the original Query

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:

enter image description here

Hope this should help you.

like image 39
Imad Alazani Avatar answered Oct 20 '22 20:10

Imad Alazani