12

I am using a generic error page using ASP.NET's <customErrors> directive.

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

Problem - when an error occurs, this page does not return HTTP status "500". It comes as 200. So link checkers and spiders do not see that there is any problem.

How can I send the 500 HTTP status along with the static 500.html page?

Requirements:

  • I must use redirectMode="ResponseRewrite"
  • I can't use a dynamic page, only static .html.
pnuts
  • 58,317
  • 11
  • 87
  • 139
frankadelic
  • 20,543
  • 37
  • 111
  • 164

6 Answers6

8

The MSDN documentation for the customErrors element states that it is implemented by System.Web.Configuration.CustomErrorsSection. If we use Red Gate's .NET Reflector to analyze that class, we can see where that setting is used in the Framework.

It is used by System.Web.UI.Page.HandleError and System.Web.HttpResponse.ReportRuntimeError.

Both of these end up calling System.Web.HttpResponse.RedirectToErrorPage. (The name of this method is confusing: it is important to note that RedirectToErrorPage takes the redirectMode setting as a parameter, so it is called even if you are using ResponseRewrite and no redirection actually happens.)

The relevant part of the RedirectToErrorPage method is:

    if (redirectMode == CustomErrorsRedirectMode.ResponseRewrite)
    {
        this.Context.Server.Execute(url);
    }

There doesn't appear to be any way to set the response code in the error handling: at the end of the day it's just a plain Server.Execute. It therefore seems unavoidable that you would need to write code to achieve the HTTP response you want.

Can you re-examine why you want to use a plain .html file? This seems a sensible choice for error handling, because you don't want to go through all the overhead of a .aspx page when that might cause another error to occur.

But perhaps there is some middle ground which will be just as robust as a .html file?

For example, you could make a precompiled HttpHandler, register it to the URL /500.error, and then make 500.error your defaultRedirect page. (This would be similar to how ScriptResource.axd works.) If you precompile your module into a DLL (as opposed to on-the-fly compilation from a plain old .axd file), you may find it is just as robust in the face of error conditions. If you encounter an error where not even this will work, then a static .html file probably won't work either -- keep in mind that the customErrors directive still relies on .NET running under the hood, and still uses the StaticFileHandler to serve your .html file.

Alternatively you could consider a reverse proxy in front of your IIS application which would serve a friendly 500 page even in the face of catastrophic failure of the application pool. This would be more work to set up, but would be even more robust than customErrors, e.g. if your web.config becomes corrupted, even customErrors won't work.

David James
  • 525
  • 3
  • 6
  • 1
    You raise a good point that is dependent on ASP.NET. I was using 500.html to get around the dependency on ASP.NET, but it is moot if the ASP.NET is not responsive. I think my best bet is to use a 500.aspx in , and have a backup 500.html Error Page configured at the IIS level in case ASP.NET is down. – frankadelic Dec 22 '10 at 22:11
4

In your gllobal.asax file add the following code

protected void Application_EndRequest(object sender, EventArgs e)
    {
        if (Request.Url.AbsolutePath.EndsWith("500.html"))
            Response.StatusCode = 500;
    }
Vinay B R
  • 8,089
  • 2
  • 30
  • 45
  • Does this require IIS7 + Integrated Pipeline? Requests for .html would otherwise not fire Application_EndRequest.. – frankadelic Aug 23 '10 at 16:10
  • sorry i did not pay attention to the error page extension being html, is there any problem with it being a aspx page. you would not have to worry IIS in that case. Also if i am not wrong iis 6 should also have ways to redirect html request to aspnet handlers. i do not have access to a machine with iis 6 installed right now – Vinay B R Aug 23 '10 at 17:57
  • see my second bullet point ... it needs to be a static html file. – frankadelic Aug 24 '10 at 00:55
  • Not sure y it cant be a aspx page. you can try this in iis 6 you can redirect html requests to asp.net by changing the application configuration of your website as follows. In your website properties under HomeDirectory tab, click on configuration button. Your can map html to aspnet_isapi dll. – Vinay B R Aug 24 '10 at 05:07
3

OK, I have a solution, the only way I can get this to work is by bypassing the custom errors section in the web configuration file.

So, an example default.aspx

public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        throw new Exception("boom");
    }
}

Then in the global.asax file:

protected void Application_Error(object sender, EventArgs e)
{
    // Clear the error to take control of process
    Server.ClearError();

    Response.WriteFile(Server.MapPath("500.html"));
    Response.StatusCode = 500;
    Response.StatusDescription = "Internal Server Error";
}

You can probably write a better handling mechanism for the 500.html part - I think this should do what you are trying to achieve.

Only tested with VS Cassini web server, however I see no reason why this shouldn't work in iis6.

Adam Jenkin
  • 4,142
  • 6
  • 25
  • 31
1

Try configuring your custom errors section like this:

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

In your 500.aspx file, change the response code in the page_load;

Response.StatusCode = 500;
Response.StatusDescription = "Internal Server Error";
Adam Jenkin
  • 4,142
  • 6
  • 25
  • 31
  • I need to use redirectMode="ResponseRewrite", so this is not an option for me. – frankadelic Aug 20 '10 at 15:56
  • Also, your solution not send a 500 HTTP status... As written, it performs a 302 redirect to 500.html. 500.html itself has a 200 HTTP status. Check it in firebug. – frankadelic Aug 20 '10 at 19:36
  • modified answer for question. – Adam Jenkin Aug 23 '10 at 11:46
  • I have now tried the above with a 404 instead of 500 (easier to generate) and the method definitely works. ResponseRewrite ensures no re-directs and the StatusCode gets set (have checked with response builder in fiddler) – Adam Jenkin Aug 23 '10 at 21:01
  • 4
    Adam, your code redirects to a file 500.aspx. See my requirements - this needs to be a static .html file, not .aspx. – frankadelic Aug 24 '10 at 00:56
  • Appologies frankedelic, I did notice this last night.. I have been trying to get it working with a static file using the server.transfer() method but not able to change the status code. of interest, how are you generating your 500 error for testing? – Adam Jenkin Aug 24 '10 at 07:31
  • To generate a 500 error, you can just throw an exception on an ASPX page. This invokes a 500 error. – frankadelic Aug 24 '10 at 16:00
0

This could be done with an isapi filter. It would have to be written in c, but it can modify the response status for the .html request so that the browser gets a 500 with you custom html page.

Mike
  • 3,462
  • 22
  • 25
-1

If you insist on changing the core HTTP signaling then you either have to give in on some demands or be prepared to write your own web server. Yes you have to run IIS7 integrated AppPool and you still may have to accept redirection to and active page since you are trying to fake that your server is down and server is not designed to fake suicide. So if it gives you one slim way to do it, your options are to either say thanks or develop your own, non-HTTP compliant server which will scramble response codes at will.

ZXX
  • 4,684
  • 27
  • 35
  • Try this: Create a classic .asp page with division by zero (1/0) and execute it. You will see that a static error page returns and HTTP status is indeed 500 (confirm using firebug or fiddler2). It's not server death/suicide, it just means that an error occurred. No "core http signaling" was changed. You can reconfigure the error page content using IIS manager > Error Pages... My issue is that this setting does not apply to .aspx pages. I can put a redirect to a .html file in in web.config, but the resulting page returns a 200 status. – frankadelic Dec 22 '10 at 22:04
  • are you saying that for an internal server error (for example from an exception) the correct http status code is 302? or 200? is returning a 302 or 200 status code NOT extremely scrambled? :-> – Myster Mar 21 '11 at 21:09
  • The only thing which is "scrambled" is ASP.NET handling of error codes. Throwing an exception and returning and error page should not produce a response code of 200 or 302. It should be 500 to indicate "something broke". – Gerald Davis Mar 18 '14 at 07:28