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 <customErrors>
to 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
Does this comment system work?