How to display a custom error page when Request Validation Exceptions are thrown?

5.4k views Asked by At

We've configured our custom error pages as below for exceptions thrown by ASP.NET:

<customErrors mode="On" redirectMode="ResponseRewrite">
  <error statusCode="400" redirect="~/400.aspx"/>
  <error statusCode="404" redirect="~/404.aspx"/>
  <error statusCode="500" redirect="~/500.aspx"/>
</customErrors>

Setting redirectMode="ResponseRewrite" is important as it ensures the URL does not change (I believe ASP.NET performs a Server.Transfer instead of Response.Redirect).

Unfortunately this does not work for Request Validation Errors. For example, with custom errors enabled if I navigate to /some/page/<script> ASP.NET's request validation kicks in and a HttpException is thrown. However instead of displaying my custom error page I get the following message:

Server Error in '/' Application.

Runtime Error

Description: An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.

Why is it that ASP.NET can not display my custom error page in this scenario? There is no code in the error page, just HTML so I know that the error page itself is not throwing any exceptions.

Also, if I catch the error myself in Application_Error and issue a Server.Transfer it works fine so I'm curious what ASP.NET is doing under the covers.

If we are to handle this ourselves, is there a better solution than this?

protected void Application_Error(object sender, EventArgs e)
{
    var ex = Server.GetLastError() as HttpException;
    if (ex != null 
        && ex.Message.StartsWith("A potentially dangerous Request.Path value was detected from the client")
        && HttpContext.Current.IsCustomErrorEnabled)
    {
        Server.Transfer("400.aspx");
    }
}
4

There are 4 answers

0
JohnH On

An issue with using the customErrors settings in a config file is that the redirection generated can cause a redirection HTTP status code (300 series) to be returned to the client/browser when you really wanted to send a server error HTTP status code (500 series) or a client error HTTP status code (400 series).

To examine the HTTP status code returned by your website you can use Chrome's "More tools > Developer tools" display with the "Network" tab selected. Then you'll be able to see the HTTP status code returned by your web server back to the client/browser. If an invalid email address login was entered, a client error status should be returned (HTTP status 400 series) and not a redirection status code (300 series).

The "Runtime time" error listed with your question may have been caused by an unhandled validation condition which generated a server error. Such errors require further attention, but should return a server error code (500 series) in the HTTP response.

Web server errors are handled at two levels. One level is in the page content display, the other is in the returned HTTP status codes. Ideally, these will be consistent with one another.

0
Remy On

Place existingResponse="Replace" and subStatusCode="-1" in the httpErrors section of your web.config.

The page now comes up as 400 error and will display your error page.

In your application
enter image description here

In your web.config enter image description here

No need to use customErrors section

enter image description here
* #8 is a page where I generate a 500 error on purpose.

2
Lesmian On

To be sure that you not omit any error codes that could occur in you webapp you can add default error page:

<customErrors mode="On" defaultRedirect="Error.aspx" />

And if you want to catch only RequestValidationErrors than you can handle it in your global.asax file:

 void Application_Error(object sender, EventArgs e)
 {
    Exception ex = Server.GetLastError();
    if (ex is HttpRequestValidationException)
    {
        Server.ClearError();
        Response.Redirect("RequestValidationError.aspx", false);
    }
 }
0
RezaGhahari On
 void Application_Error(object sender, EventArgs e) {
    Exception Ex = Server.GetLastError;
    Logger.AddNewLog(Logger.LogType.ErrorLog, sender.ToString, "Error", (Ex.Message 
                    + (Environment.NewLine + Ex.StackTrace)));
    Server.ClearError();
    Response.Redirect("/Error");
}