ASP.NET MVC4 CustomErrors DefaultRedirect Ignored

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.

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.