Search code examples
asp.netasp.net-mvchttp-status-code-404custom-error-pages

ASP.NET MVC custom error page not working correctly


I'm trying to configure ASP.NET MVC custom error pages.

I added an Error controller with Index and PageNotFound actions. I also added the following to the <system.web> section of my web.config file.

<customErrors mode="On" defaultRedirect="~/Error">
  <error statusCode="404" redirect="~/Error/PageNotFound"/>
  <error statusCode="500" redirect="~/Error" />
</customErrors>

If I type in a URL such as http://www.example.com/Home/BadPage, I do in fact see my error handler.

However, can anyone help me understand the following issues and how to work around them?

  1. In the case above, it appears that the result code returned to the browser is 200 and not 404. So crawlers such as Google's would have no indication the URL was not found.
  2. In some cases, if my controller action determines the URL is not valid, the action will return HttpNotFound() as the result. But when this happens, my custom error handler page is not displayed. Instead it shows a generic 404 page that appears to be from IIS.

I'm using the current versions of Visual Studio and MVC.


Solution

  • In addition to setting inside web.config, you also want to check whether Exception is HttpException 404 inside Application_Error.

    <customErrors defaultRedirect="~/Common/Error" mode="On">
      <error statusCode="404" redirect="~/Common/PageNotFound"/>
    </customErrors>
    

    Global.asax.cs

    protected void Application_Error(object sender, EventArgs e)
    {
        var exception = Server.GetLastError();
    
        // Process 404 HTTP errors
        var httpException = exception as HttpException;
        if (httpException != null && httpException.GetHttpCode() == 404)
        {
            Response.Clear();
            Server.ClearError();
            Response.TrySkipIisCustomErrors = true;
    
            IController controller = new CommonController();
    
            var routeData = new RouteData();
            routeData.Values.Add("controller", "Common");
            routeData.Values.Add("action", "PageNotFound");
    
            var requestContext = new RequestContext(
                 new HttpContextWrapper(Context), routeData);
            controller.Execute(requestContext);
        }
    }
    

    CommonController

    You also want to return Response.StatusCode = 404; inside PageNotFound action method.

    public class CommonController : Controller
    {
        [AllowAnonymous]
        public ActionResult PageNotFound()
        {
            Response.StatusCode = 404;
            Response.TrySkipIisCustomErrors = true;
    
            return View();
        }
    
        [AllowAnonymous]
        public ActionResult Error()
        {
            Response.StatusCode = 503;
            Response.TrySkipIisCustomErrors = true;
    
            return View();
        } 
    }