ASP.NET Custom Errors: Preventing 302 Redirects To Custom Error Pages

by Colin Cochrane 1/25/2008 9:53:42 PM
 
You can download the HttpModule here.
 
Defining custom error pages is a convenient way to show users a friendly page when they encounter an HTTP error such as a 404 Not Found, or a 500 Server Error.  Unfortunately ASP.NET handles custom error pages by responding with a 302 Temporary redirect to the error page that was defined. For example, consider an example application that has IIS configured to map all requests to it, and has the following customErrors element defined in its web.config:
 
<customErrors mode="RemoteOnly" defaultRedirect="~/error.aspx">
<error statusCode="404" redirect="~/404.aspx" />
</customError>

If a user requested a page that didn't exist, then the HTTP response would look something like:

http://www.domain.com/non-existant-page.aspx --> 302 Found
http://www.domain.com/404.aspx  --> 404 Not Found
Date: Sat, 26 Jan 2008 03:08:21 GMT
Server: Microsoft-IIS/6.0
Content-Length: 24753
Content-Type: text/html; charset=utf-8
X-Powered-By: ASP.NET
 
As you can see, there is a 302 redirect that occurs to send the user to the custom error page.  This is not ideal for two reasons:

1) It's bad for SEO

When a search engine spiders crawls your site and comes across a page that doesn't exist, you want to make sure you respond with an HTTP status of 404 and send it on its way.  Otherwise you may end up with duplicate content issues or indexing problems, depending on the spider and search engine.

2) It can lead to more incorrect HTTP status responses

This ties in with the first point, but can be significantly more serious.  If the custom error page is not configured to response with the correct status code then the HTTP response could end up looking like:

http://www.domain.com/non-existant-page.aspx --> 302 Found
http://www.domain.com/404.aspx  --> 200 OK
Date: Sat, 26 Jan 2008 03:08:21 GMT
Server: Microsoft-IIS/6.0
Content-Length: 24753
Content-Type: text/html; charset=utf-8
X-Powered-By: ASP.NET
 
Which would almost guarantee that there would be duplicate content issues for the site with the search engines, as the search spiders are simply going to assume that the error page is a normal page, like any other.Furthermore it will probably cause some website and server administration headaches, as HTTP errors won't be accurately logged, making them harder to track and identify.
I tried to find a solution to this problem, but I didn't have any luck finding anything, other than people who were also looking for a way to get around it.  So I did what I usually do, and created my own solution.
 
The solution comes in the form of a small HTTP module that hooks onto the HttpContext.Error event.  When an error occurs, the module checks if the error's type is an HttpException.  If the error is an HttpException, then the following process takes place:
  1. The response headers are cleared (context.Response.ClearHeaders() )
  2. The response status code is set to match the actual HttpException.GetHttpCode() value (context.Response.StatusCode = HttpException.GetHttpCode())
  3. The customErrorsSection from the web.config is checked to see if the HTTP status code (HttpException.GetHttpCode() ) is defined.
  4. If the statusCode is defined in the customErrorsSection then the request is transferred, server-side, to the custom error page. (context.Server.Transfer(customErrorsCollection.Get(statusCode.ToString).Redirect) )
  5. If the statusCode is not defined in the customErrorsSection, then the response is flushed, immediately sending the response to the client.(context.Response.Flush() )

Here is the source code for the module.

   1: Imports System.Web
   2: Imports System.Web.Configuration
   3:  
   4: Public Class HttpErrorModule
   5:   Implements IHttpModule
   6:  
   7:   Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
   8:     'Nothing to dispose.
   9:   End Sub
  10:  
  11:   Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
  12:     AddHandler context.Error, New EventHandler(AddressOf Context_Error)
  13:   End Sub
  14:  
  15:   Private Sub Context_Error(ByVal sender As Object, ByVal e As EventArgs)
  16:     Dim context As HttpContext = CType(sender, HttpApplication).Context
  17:     If (context.Error.GetType Is GetType(HttpException)) Then
  18:       ' Get the Web application configuration.
  19:       Dim configuration As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration("~/web.config")
  20:  
  21:       ' Get the section.
  22:       Dim customErrorsSection As CustomErrorsSection = CType(configuration.GetSection("system.web/customErrors"), CustomErrorsSection)
  23:  
  24:       ' Get the collection
  25:       Dim customErrorsCollection As CustomErrorCollection = customErrorsSection.Errors
  26:  
  27:       Dim statusCode As Integer = CType(context.Error, HttpException).GetHttpCode
  28:  
  29:       'Clears existing response headers and sets the desired ones.
  30:       context.Response.ClearHeaders()
  31:       context.Response.StatusCode = statusCode
  32:       If (customErrorsCollection.Item(statusCode.ToString) IsNot Nothing) Then
  33:         context.Server.Transfer(customErrorsCollection.Get(statusCode.ToString).Redirect)
  34:       Else
  35:         context.Response.Flush()
  36:       End If
  37:  
  38:     End If
  39:  
  40:   End Sub
  41:  
  42: End Class

The following element also needs to be added to the httpModules element in your web.config (replace the attribute values if you aren't using the downloaded binary):

<httpModules>
<add name="HttpErrorModule" type="ColinCochrane.HttpErrorModule, ColinCochrane" />
</httpModules>

And there you go! No more 302 redirects to your custom error pages.

Tags: ,

ASP.NET | SEO | Web Development

Comments (42) -

1/25/2008 10:32:33 PM

Thank you so much!  I've been bashing my head against the wall trying to figure out why one of our client's sites kept responding with all of those 302's.  I'll definitely be giving this a try.

James United States

1/25/2008 11:12:34 PM

Tried it out tonight and it worked like a charm.

Thank you!

Eric United States

2/5/2008 5:13:18 AM

Hi I like this Article too much , but can u provide this Article in C#, I will b too thankfull to you.

Abhiahek India

3/4/2008 1:30:55 AM

Here is the C# translation for anyone to use

using System.Web;
using System.Web.Configuration;
using System;

public class HttpErrorModule : IHttpModule
{

    private void Context_Error(object sender, EventArgs e)
    {
        HttpContext context = ((HttpApplication)sender).Context;
            if((object.ReferenceEquals(context.Error.GetType(),typeof(HttpException))))
            {
            // Get the Web application configuration.
            System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~/web.config");
            // Get the section.
            CustomErrorsSection customErrorsSection = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");
            // Get the collection
            CustomErrorCollection customErrorsCollection = customErrorsSection.Errors;
            int statusCode = ((HttpException)context.Error).GetHttpCode();

            //Clears existing response headers and sets the desired ones.
            context.Response.ClearHeaders();
            context.Response.StatusCode = statusCode;

            if ((customErrorsCollection.Get(statusCode.ToString()) != null))
            {
                context.Server.Transfer(customErrorsCollection.Get(statusCode.ToString()).Redirect);
            }

            else
            {
                context.Response.Flush();
            }
        }
    }

    #region IHttpModule Members

    public void Dispose()
    {
      //Do nothing here
    }

    public void Init(HttpApplication context)
    {
        context.Error += new EventHandler(Context_Error);
    }

    #endregion
}

Sammy Canada

3/4/2008 8:35:35 AM

Thanks Sammy!  

Colin Cochrane Canada

3/10/2008 5:33:43 PM

Some months backs, I had a discussion about the same topic in the following thread over at the ELMAH discussion group:
groups.google.com/.../d01b003b37b023c7

I'm glad to see that someone has finally brought the problem to public light. I'll be sure to point to this post in the future as I hop from one ASP.NET soul to another trying to hopelessly explain how custom error handling in ASP.NET is broken.

Apart from spiders, the 302-style custom error handling breaks any kind of client-side code that deals with parsing or downloading of web resources. Imagine using System.Net.WebClient.DownloadFile to download a ZIP file from a URL that results in an error (perhaps denial of authorization). The web site will respond with a 302 followed by 200. The ZIP will be reported to have downloaded successfully yet any decompression tool will find the archive to be corrupted. It will be corrupted because its content will reflect the customer error page. Tong I have found that the corruption scenario gets people more nervous and itching to address the issue in their sites than, say, the argument regarding search engines and SEO.

BTW, you might want to add a check for Context.IsCustomErrorEnabled in the module. This way, it will adapt automatically between production and development environments since one tends to configure customer error pages such that they're disabled during development (to get the yellow screen of death) but enabled in production.

Atif Aziz

4/22/2008 2:19:56 PM

Awesome module! I've been testing it out on my local machine and the 404 errors work flawlessly, but I can't get the 500 errors to work without redirecting. Every time I trigger an error somewhere it ignores your module and does that redirect spiel. Does anyone have a work around? Thanks!

Kenpachi United States

4/25/2008 9:05:40 AM

Kenpachi - Would you mind showing us your web.config?

Colin Cochrane Canada

5/21/2008 11:04:40 AM

Does it work on windows 2000 server standard?

Tommy Vallée Canada

5/21/2008 11:48:39 AM

Hi,

i'm such a newbie with this so i have a few questions :

where do i put the DLL???
How can i actve the httpmodule??

In Fact, I don't know what to do with the dll Smile

I'm running IIS 5

Thanks Colin

Brent United States

5/21/2008 12:06:06 PM

Tommy - There's no reason it shouldn't.  All that is required is ASP.NET 2.0.


Brent - The DLL should be placed in the /bin directory of the application.  

Colin Cochrane Canada

5/27/2008 10:18:35 AM

ok and Which application are you taling about.. i'm not a pro with that.

Brent United States

5/29/2008 8:57:15 PM

You'll be looking for the root directory of your website (application just means web application).

Colin Cochrane Canada

6/10/2008 9:39:26 AM

I can't seem to get this to work in my VS 2008 project.  I have tried both copying the .dll to my bin directory, and have also tried putting my own .vb file in the app_code directory.  I have registered the module in the httpModules section of system.web in my web.config file, both using your line of code, and a modified line of code to match my custom .vb file (using your source code listed above).

What could I be doing wrong?

VS.NET 2008, 3.5, Vista, Debugging on IIS.

klint United States

6/10/2008 2:29:04 PM

@klint:

Try setting a breakpoint at the Init() procedure in the module and see if it gets hit. If it doesn't get hit, then we'll know the module isn't being loaded properly.

Colin Cochrane Canada

6/10/2008 2:59:12 PM

It does not get hit.

I have posted a question on forums.asp.net and your feedback would be greatly appreciated.

<system.web>
<httpModules>
            <add name="HttpErrorModule" type="HttpErrorModule, HttpErrorModule" />
</httpModules>
</system.web>

I have tried turning errors Off, On, RemoteOnly and commenting out the entire section

    <customErrors mode="Off" defaultRedirect="~/Error.aspx">
            <error statusCode="403" redirect="~/403Forbidden.aspx" />
            <error statusCode="404" redirect="~/404PageNotFound.aspx" />
    </customErrors>

I have created HttpErrorModule.vb in the App_Code directory (code listed below)

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

......
(rest of code omitted)

klint United States

6/10/2008 2:59:37 PM

http://forums.asp.net/t/1273530.aspx

klint United States

6/10/2008 4:44:30 PM

when I add the breakpoint, and debug, instead of the red dot, I get a white dot outlined in red, with a little yellow exclamation point.

Hovering over it, VS states:

At HttpErrorModule.vb, line 12 character 12 (Init,line2)

The breakpoint will not currently be hit. No symbols have been loaded for this document

klint United States

6/10/2008 4:45:35 PM

i thought that perhaps the HttpErrorModule is a reserved word, so I changed it to myHttpErrorModule.  Still no dice.

It also appears the VS is not compiling .vb files into a .dll in the bin directory

klint United States

6/10/2008 5:14:12 PM

well, now I am convinced it is not even listening to requests.

I added the following line to init

Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
        <b>Throw New HttpException("Exception Occured")</b>
        AddHandler context.Error, New EventHandler(AddressOf Context_Error)
    End Sub

When I start the debugger, it just loads the home page and does not throw the error.

My web.config now includes this:

<system.web>
<httpModules>
<add name="myHttpErrorModule" type="myHttpErrorModule" />
</httpModules>
</system.web>

Did something change in IIS 7 or VS 2008 that changes the way iHTTPModules are implemented?

klint United States

6/10/2008 9:15:40 PM

Klint: Could you post the contents of your web.config?

Colin Cochrane Canada

6/12/2008 2:52:23 PM

<?xml version="1.0"?>
<!--
    Note: As an alternative to hand editing this file you can use the
    web admin tool to configure settings for your application. Use
    the Website->Asp.Net Configuration option in Visual Studio.
    A full list of settings and comments can be found in
    machine.config.comments usually located in
    \Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration>
  <configSections>
    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
        <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
        <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
          <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
          <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
          <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
          <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
        </sectionGroup>
      </sectionGroup>
    </sectionGroup>
  </configSections>
  <appSettings>
    <add key="smtpServerAddress" value="localhost"/>
  </appSettings>
  <connectionStrings />
  <system.web>
    <!--
            Set compilation debug="true" to insert debugging
            symbols into the compiled page. Because this
            affects performance, set this value to true only
            during development.

            Visual Basic options:
            Set strict="true" to disallow all data type conversions
            where data loss can occur.
            Set explicit="true" to force declaration of all variables.
        -->
    <compilation debug="true" strict="false" explicit="true">
      <assemblies>
        <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies>
    </compilation>
    <pages>
      <namespaces>
        <clear/>
        <add namespace="System"/>
        <add namespace="System.Collections"/>
        <add namespace="System.Collections.Generic"/>
        <add namespace="System.Collections.Specialized"/>
        <add namespace="System.Configuration"/>
        <add namespace="System.Text"/>
        <add namespace="System.Text.RegularExpressions"/>
        <add namespace="System.Linq"/>
        <add namespace="System.Xml.Linq"/>
        <add namespace="System.Web"/>
        <add namespace="System.Web.Caching"/>
        <add namespace="System.Web.SessionState"/>
        <add namespace="System.Web.Security"/>
        <add namespace="System.Web.Profile"/>
        <add namespace="System.Web.UI"/>
        <add namespace="System.Web.UI.WebControls"/>
        <add namespace="System.Web.UI.WebControls.WebParts"/>
        <add namespace="System.Web.UI.HtmlControls"/>
      </namespaces>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </controls>
    </pages>
    <!--
            The <authentication> section enables configuration
            of the security authentication mode used by
            ASP.NET to identify an incoming user.
        -->
    <authentication mode="Windows"/>
    <!--
            The <customErrors> section enables configuration
            of what to do if/when an unhandled error occurs
            during the execution of a request. Specifically,
            it enables developers to configure html error pages
            to be displayed in place of a error stack trace.
    -->
    
    
        <customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx">
            <error statusCode="403" redirect="~/403Forbidden.aspx" />
            <error statusCode="404" redirect="~/404PageNotFound.aspx" />
        </customErrors>
    
    
    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
    </httpHandlers>
    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <!--<add type="YourModuleNameHere.IPBlackList, YourAssemblyNameHere" name="IPBlackList" />-->
      <!--<add name="HttpErrorModule" type="ColinCochrane.HttpErrorModule, ColinCochrane" />-->
      <add name="myHttpErrorModule" type="myHttpErrorModule" />
    </httpModules>
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <providerOption name="CompilerVersion" value="v3.5"/>
        <providerOption name="WarnAsError" value="false"/>
      </compiler>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <providerOption name="CompilerVersion" value="v3.5"/>
        <providerOption name="OptionInfer" value="true"/>
        <providerOption name="WarnAsError" value="false"/>
      </compiler>
    </compilers>
  </system.codedom>
  <!--
        The system.webServer section is required for running ASP.NET AJAX under Internet
        Information Services 7.0.  It is not necessary for previous version of IIS.
    -->
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <remove name="ScriptModule"/>
      <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-Integrated"/>
      <remove name="ScriptHandlerFactory"/>
      <remove name="ScriptHandlerFactoryAppServices"/>
      <remove name="ScriptResource"/>
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

klint United States

6/12/2008 4:30:27 PM

I figured it out and posted my closing comments on the asp.net forums

forums.asp.net/p/1273530/2420415.aspx#2420415

Thank you for your assistance.

klint United States

6/13/2008 7:34:19 AM

Sigh. Still not working.  I figured out how to get the module to load within IIS 7, but according to fiddler, it is not sending the 404 code.

This is in both my own code, and your module.

Have you verified this works in IIS 7 in integrated mode?

klint United States

6/13/2008 7:58:32 PM

I've had no problems with IIS7 in integrated mode.  Is it still throwing a 302 redirect to the error page?  If not, make sure that the error pages are configured to clear the response headers and set the status code.

eg)

void page_load(Object sender, EventArgs e){
  Response.ClearHeaders();
  Response.StatusCode = 404;

}

Colin Cochrane

6/14/2008 9:50:44 AM

Yes, it still throws a 302, and then a 200.  

Yes, I had already added:

Response.ClearHeaders();
Response.StatusCode = 404;

klint United States

6/14/2008 4:03:04 PM

You said this was on your local machine?  Trying changing the customErrors mode to "On" instead of "RemoteOnly".

Colin Cochrane

9/3/2008 12:09:37 PM

I have tried to use this control and have found that it does run but I show a 302 found header is received before a 200 ok header. I am using the following server setup.

Microsoft .NET Framework Version:2.0.50727.1433; ASP.NET Version:2.0.50727.1433

Windows Server 2003

Microsoft-IIS/6.0

I have put your dll in the bin holder. I had to modify the web.config section just a little to get it to run.


<configuration>
  <system.web>
    <httpModules>
      <add name="HttpErrorModule" type="ColinCochrane.HttpErrorModule, ColinCochrane.HttpErrorModule" />
    </httpModules>

    <customErrors mode="On">
      <error statusCode="404" redirect="/goto/404.aspx" />
    </customErrors>
  </configuration>
</system.web>

I am using a hosting service and do not have access to the iis control panel. Any idea if I have done something wrong?

Thanks

Mark United States

9/9/2008 8:46:57 AM

I haven't been able to get this to work.  I created a new assembly called "ctca" (company name), i have one namespace called "httpModules", and i have one class called "httpErrorModule".  The code is the exact copy of the one in this post.  Below is my web.config httpModules section:

<httpModules>
<add name="HttpErrorModule" type="ctca.HttpModules.HttpErrorModule,ctca" />
</httpModules>

<customErrors mode="Off">
  <error statusCode="500" redirect="~/errors/500.htm"/>
  <error statusCode="404" redirect="~/errors/404.htm"/>
</customErrors>

Also, i am using Windows 2003, with IIS 6.0, and Default Pool. If I set the mode="on" in my customErrors section it does the redirect with a 302 status code.

Dhaval

dhaval United States

10/15/2008 4:25:51 PM

Once I add this httpmodule in the web.config, I am getting the following error

Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration>\<system.web>\<httpModules> section in the application configuration.

when I remove this line from web.config, my website works again with no problems.

Any ideas?

Thanks

Arun United States

10/15/2008 4:29:10 PM

I did not have  System.Web.SessionStateModule  in my web.config before, but i never had problems using session variables. but I am getting this error message after adding this httpmodule(<add name="HttpErrorModule" type="ColinCochrane.HttpErrorModule, ColinCochrane" />
) in web.config.

After getting this error message, I added
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>   to httpmodules section in web.config.  But that does not fix the issue.

Arun United States

11/2/2008 6:54:37 PM

im doing a login module and wanted to redirect it to a 401 error page if the login is incorrect. i did try this but it still goes to a 302 then 200 after.

chitgoks Philippines

11/2/2008 11:22:18 PM

I placed my c# code in ~/App_code/com/http/error/HttpErrorModule.cs since my namespace is in com.http.error

also placed in the web.config

<httpModules>
      <add name="HttpErrorModule" type="com.http.error.HttpErrorModule" />
    </httpModules>

    <customErrors mode="Off" defaultRedirect="~/error_page/error.html">
      <error statusCode="404" redirect="~/page_not_found.html" />
      <error statusCode="401" redirect="~/error_page/access_denied.html" />
    </customErrors>

and my context.Response.StatusCode = statusCode; will always output 302, then 200 still.

these are the only things that are needed right? or am i missing something here? thank you

chitgoks Philippines

1/5/2009 8:00:41 AM

This is an excellent article!  I have learned a great deal from how errors are handled in ASP.NET.

However, I'm still having an issue that may be related, that I hope someone here can help me with.  My problem is that I'm not seeing an error caught here (or anywhere else) for a 404. All I get is the stock 404 page.  I've tried virtually every possible combination of the customerrors section, to no avail.  One possible item of note, is that I am working on a frame based site (yeah I know, not my call!)

Mark United States

1/6/2009 3:42:59 PM

A better approach if your web hosting provider is using the latest .NET service pack (3.5 SP1, 3.0 SP2, 2.0 SP2) is to use the new redirectMode:

msdn.microsoft.com/.../...ection.redirectmode.aspx

<customErrors mode="RemoteOnly" defaultRedirect="~/error.aspx" redirectMode="ResponseRewrite">
  <error statusCode="404" redirect="~/404.aspx" />
</customErrors>

Another consideration is what should happen when a programming error occurs. As far as I can tell the search engine would currently index the error page for the url (with 302 and now 200) where instead you want to tell it not to index temporarily and try again later (503 seems best match). Therefore I'm putting this in Global.asax file:

void Application_Error(object sender, EventArgs e) {
  //if error is an httpexception, the response status code will automatically be set e.g. 404
  if (Context.Error.GetType() != typeof(HttpException))
    Context.Response.StatusCode = 503;
}

Michael New Zealand

2/2/2009 9:57:00 AM

@Michael,

Thanks for the heads-up on that. I'll definitely be looking into that new feature.

Colin Cochrane Canada

4/22/2009 8:25:35 AM

Thanks Colin, that was exactly what I was looking for! Everyone, make sure you have customErrors set to Off or RemoteOnly. This module actually takes the place of ASP.Net's error handling. It still reads the contents of the node but you need to tell ASP.Net not to handle things for you. Also, if you have IIS redirecting to the same page make sure you've added a Response.StatusCode = 404 in the Page_Load. I've gone deeper into the article along with how to add it to your App_Code here:
blog.vendiadvertising.com/.../...)-404-errors.aspx

Chris Haas United States

6/3/2009 7:55:24 AM

For me your code doesn't work on Win2003 with IIS6 server, after request to folder that back 404 error ASP.NET don't see that request at all, any work arround for that without configurating IIS6 on server.

Demon

6/8/2009 10:28:17 AM

My simple fix for asp.net 404 errors and google showing text instead of a PageNotFound.aspx page. Created an htm page with a redirect that points to the aspx and then set IIS Custom Errors for 404 to point to the htm page. Google now correctly shows the aspx page not found page.

al miller United States

8/18/2009 12:40:37 AM

I think there are templates specially designed for Custom error pages, not sure about blogengine though.

Mike United States

9/15/2009 9:46:30 PM

One problem with the new RedirectMode setting is that it doesn't support MVC routes. Ironically, if you enable customErrors with RedirectMode="ResponseRewrite" and then set your redirect paths to a controller route (say ~/Error/NotFound) you end up getting a YSOD which informs you that you can display the error contents by turning off customErrors... Whoops!

Nathan United States

8/19/2011 12:29:23 PM

Hi , thank you for letting me leaving a comment on your site ASP.NET Custom Errors: Preventing 302 Redirects To Custom Error ..., it is always nice to see that blogowners are interested in their visitors.

John

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

Powered by BlogEngine.NET 2.5.0.6

All Content and Intellectual Property is under Copyright Protection | Colin Cochrane ©2007

About the author

Colin Cochrane

Colin Cochrane

SEO and ASP.NET Developer.

Recent comments

Recent posts

Archive

Authors

Disclaimer

This is a personal weblog. The opinions expressed here represent my own and not those of my employer. © Copyright Colin Cochrane 2014

Sign in