asp.net-mvciishttp-errorcustom-errors

HTTP errors not consistent using customErrors mode="On"


I am testing custom error handling using similar URLs http://localhost:52200/< and http://localhost:52200/<xyz. Somehow, I am getting inconsistent results.

Web.Config:

<!--MVC pipeline-->
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
    <error statusCode="404" redirect="~/404.aspx" />
    <error statusCode="500" redirect="~/500.aspx" />
</customErrors>

<!--IIS pipeline-->
<httpErrors errorMode="Custom">
  <remove statusCode="404"/>
  <error statusCode="404" path="404.html" responseMode="File"/>
  <remove statusCode="500"/>
  <error statusCode="500" path="500.html" responseMode="File"/>
</httpErrors>

When customErrors mode="Off", both return identical HTTP 400 Bad Request:

enter image description here

However, when customErrors mode="On", only http://localhost:52200/< returns HTTP 400 Bad Request and then redirects to Error.aspx.

Now, http://localhost:52200/<xyz returns HTTP 500 Internal Server Error and goes to:

enter image description here

When I remove ResponseRewrite, both return HTTP 302 Found and redirect to Error.aspx. I do not want this because I lose the http error code.

What am I doing wrong?


Solution

  • Solved! For a reason unknown to me, MVC pipeline requires defaultRedirect to point toward a .html file:

    <customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Error.html">
    

    Adding Response.ContentType = "text/html"; in Global.asax.cs avoids a known issue where the error page would render as text:

    protected void Application_Error()
    {
        var exception = Server.GetLastError();
        if (exception is HttpException httpException)
        {
            Response.ContentType = "text/html";
            Response.StatusCode = httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;
        }
    }
    

    Also, Response.StatusCode ensures that the correct HTTP error code reaches the client (e.g. 400, 503, etc.) instead of a 200.

    With these 2 blocks in web.config and global.asax.cs and no change to IIS, both http://localhost:52200/< and http://localhost:52200/<a now return HTTP 400 Bad Request and display Error.html as expected.