ASP.NET 404 handling _without_ redirection

antic

Perch
Hi all,

In my .net application, I want to handle 404 errors in the "normal" way that IIS handles them for all files.
So I set up a custom 404 file in ISS as normal. For example, my custom error file is "/custom404.aspx":

wwltlf.jpg


This works fine for missing files of all types - html, css, etc. except .aspx files.
When a missing .aspx file is requested, .NET ignores IIS and uses this web.config setting instead:

Code:
<customErrors mode="On">
  <error statusCode="404" redirect="~/custom404.aspx" />
</customErrors>

That's well and good, but I don't want it to redirect. ie. I don't want the URL changed to this, eg:
/custom404.aspx?aspxerrorpath=/missingfile.aspx
I want it to stay like this, as it does for other missing files, eg:
/missingfile.html

So the question is: How do I tell .NET to handle missing .aspx files without redirecting and changing the browser's URL?

A solution would be vastly appreciated!
 
For 404 errors, you might be able to fix this by turning on "Check if file exists" for the ISAPI filter settings for the .aspx extension.

If you want to prevent the redirection for 500 errors as well, then the only way I know of is to write a HttpModule. Problem is the working example I have is written in my boss' time.

It also has the side effect of showing the full error message instead of the custom error for visitors from our office IPs. I'm still having some trouble with that.. we use McAfee Secure for some basic server audits and it keeps claiming custom errors are turned off (that's technically true) and full error messages will be shown (not true).

Anyway.. Implement IHttpModule, create an event handler for the Error event and do something like this:

Code:
void context_Error(object sender, EventArgs e)
{
	HttpContext context = ((HttpApplication)sender).Context;

	if (context.Error is HttpException)
	{
		HttpException exception = context.Error as HttpException;
		CustomErrorsSection customErrorsSection = (CustomErrorsSection)WebConfigurationManager.GetSection("system.web/customErrors");

		context.Response.ClearHeaders();
		
		// Set the actual status code, so crawlers will see the actual 404 error
		// and stop trying to index the page
		context.Response.StatusCode = exception.GetHttpCode();
		
		// Get the error page relevant to the error that occurred
		CustomError customError = customErrorsSection.Errors[context.Response.StatusCode.ToString()];

		if (customError != null)
		{
			context.Response.ClearContent();
			context.Server.Transfer(customError.Redirect);
		}
		else if (customErrorsSection.DefaultRedirect != null)
		{
			context.Response.ClearContent();
			context.Server.Transfer(customErrorsSection.DefaultRedirect);
		}
		else
			context.Response.Flush();
	}
}

The Server.Transfer will make sure the error page is shown without actually redirecting.
 
Thanks SubSpace, I experimented with global.asax code and soon found as you say that an httpModule was the way to go. Ended up using the BeginRequest event as I need to process everything that comes thru, including valid hits. Only downside is the httpException isn't set at that point, but that's no big deal. Easy to find out if the request is for an existing resource or not.

The final trick, as you have there, is the Server.Transfer. For me, I have to clear the error condition first, then do the transfer. I was scratching my head for a while, wondering why it was still saying 404 error even when I cleared the error! Turns out .NET was still looking for the non-existent URL, not the custom404 page - since it ignores what is set in IIS. So once I put the server.transfer at the end, all was good!
 
Back
Top