UPDATE: I should found out that in ASP.Net 3.5 the
<customErrors> section in web.config now supports the attribute
redirectMode which default to
ResponseRedirect but can be changed to
ResponseRewrite. This will force the proper HTTP status codes to come through for errors.
So I launched a new site porting it from static
.html files to dynamic
.aspx. I then created an entry for 404’s in web.config and also told IIS to send 404’s to the same page for everything that ASP.Net didn’t handle (images, html files, etc). So simple, right? Unfortunately both ASP.Net and IIS don’t appear to actually send a 404 status code for 404’s if you have a 404 handler specified. IIS actually sends a
200 OK and performs the equivalent of a
Server.Transfer. ASP.Net actually sends a
302 Found which is a client-side redirect.
Now, you may not care about this, but if you’re trying to purge search engines of old content you should.
The fix, at first glance, is simple. In
Page_Load on the 404 handler page just send the proper status code using
Response.StatusCode = 404. This actually fixes the problem with IIS but we’ve still got an ASP.Net problem. ASP.Net will actually still send the 302 redirecting people to the 404 page and then send the 404 code. So if page
Blah.aspx doesn’t exist you’ll get a 302 code saying to go to
PageNotFound.aspx. When the browser requests
PageNotFound.aspx they finally get the 404 response. Now maybe that’s good enough for you, but not for me. When I 404, I want to know right away, not after a redirect.
I found the solution here and have reproduced the code below for easy copy-and-paste. They don’t explicitly mention it in the article but you MUST set the
Off or at least
RemoteOnly. I know that sounds weird but the code below still actually processes the
<customErrors>, it just does it instead of letting ASP.Net handle it for you.
The article talks about creating a DLL but you can just as easily drop it into
App_Code as a file named
HttpErrorModule. Then just add
<add name="HttpErrorModule" type="HttpErrorModule" /> to your <httpModules>.
One other thing to note, this module actually overrides all errors and sends their proper codes in the response stream. This shouldn’t cause any problems but you should be aware of it when debugging. You could very easily add some logic to check for 404’s only, too.
'Code from: http://www.colincochrane.com/post/2008/01/ASP-NET-Custom-Errors-Preventing-302-Redirects-To-Custom-Error-Pages.aspx Option Strict On Option Explicit On Imports System.Web Imports System.Web.Configuration Public Class HttpErrorModule Implements IHttpModule Public Sub Dispose() Implements System.Web.IHttpModule.Dispose 'Nothing to dispose. End Sub Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init AddHandler context.Error, New EventHandler(AddressOf Context_Error) End Sub Private Sub Context_Error(ByVal sender As Object, ByVal e As EventArgs) Dim context As HttpContext = CType(sender, HttpApplication).Context If (context.Error.GetType Is GetType(HttpException)) Then ' Get the Web application configuration. Dim configuration As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration("~/web.config") ' Get the section. Dim customErrorsSection As CustomErrorsSection = CType(configuration.GetSection("system.web/customErrors"), CustomErrorsSection) ' Get the collection Dim customErrorsCollection As CustomErrorCollection = customErrorsSection.Errors Dim statusCode As Integer = CType(context.Error, HttpException).GetHttpCode 'Clears existing response headers and sets the desired ones. context.Response.ClearHeaders() context.Response.StatusCode = statusCode If (customErrorsCollection.Item(statusCode.ToString) IsNot Nothing) Then context.Server.Transfer(customErrorsCollection.Get(statusCode.ToString).Redirect) Else context.Response.Flush() End If End If End Sub End Class