Custom Error Handling in web.config / Global.asax not handling non-existant directory
Question is: Why is custom Error handling not working for non-existing paths/directories?
Updated with fixed code (thanks to everyone for you input):
* Updated code for web.config and global.asax *
<httpErrors errorMode="Custom">
<remove statusCode="500" subStatusCode="-1" />
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" subStatusCode="-1" prefixLanguageFilePath="" path="/*****.aspx" responseMode="ExecuteURL" />
<error statusCode="500" subStatusCode="-1" prefixLanguageFilePath="" path="/*****.aspx" responseMode="ExecuteURL"/>
</httpErrors>
added this to the global.asax to stop IIS from handling my 500 errors
after @Kev's suggestions IIS handled my 500's these lines fixed that
HttpApplication myApplication = new HttpApplication();
myApplication.Response.TrySkipIisCustomErrors = true;
We have a site setup with custom error handling in web.config
and global.asax
(the setup is shown below). We are able to handle all 404's and 500's with no problems. The errors are caught in the Application_Error
in the global.asax
, logged to a DB then using HttpContext
we set the status code and use Server.Transfer()
to move the user to the appropriate error page (redirects cause a 302, and hurts SEO).
The problem is when the user types in http://www.example.com/whatever
a blank page is shown in Firefox and in IE it shows the IE 404 page. Firebug shows no status codes being fired, and when I debug the solution, no breakpoints I have set are hit in the global.asax
. The odd thing is that a user can enter http://www.example.com/whatever/hmm.aspx
and an error will be hit. It seems it's only working on non-existing pages and not paths/directories that don't exist.
Below is my web.config
code for the Errors and my global.asax
code for Application error.
I've added the开发者_开发问答 ** to hide info, they have valid .aspx
pages in them:
Web config:
<customErrors defaultRedirect="~/******.aspx" mode="On"
redirectMode="ResponseRewrite">
<error statusCode="500" redirect="~/*****.aspx" />
<error statusCode="404" redirect="~/*****.aspx" />
</customErrors>
<httpErrors errorMode="Custom">
<remove statusCode="500" subStatusCode="-1" />
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" subStatusCode="-1" prefixLanguageFilePath="" path="/*****.aspx" responseMode="ExecuteURL" />
<error statusCode="500" subStatusCode="-1" prefixLanguageFilePath="" path="/*****.aspx" responseMode="ExecuteURL"/>
</httpErrors>
Code:
protected void Application_Error(Object sender, EventArgs e)
{
// At this point we have information about the error
HttpContext ctx = HttpContext.Current;
// set the exception to the Context
Exception exception = ctx.Server.GetLastError();
// get the status code of the Error
int httpCode = ((HttpException)exception).GetHttpCode();
// get the IP Address
String strHostName = string.Empty;
String ipAddress_s = string.Empty;
strHostName = System.Net.Dns.GetHostName();
System.Net.IPHostEntry ipEntry = System.Net.Dns.GetHostByName(strHostName);
System.Net.IPAddress[] addr = ipEntry.AddressList;
for (int i = 0; i < addr.Length; i++)
{
ipAddress_s += "IP Address {" + (i + 1) + "} " +
addr[i].ToString() + Environment.NewLine;
}
// setup the error info one for user display and one for the DB Insert
string errorInfo =
"<br /><b>Error Location:</b> " + ctx.Request.Url.ToString() +
"<br /><br /><b>Error Source:</b> " + exception.Source +
"<br /><br /><b>Error Try/Catch:</b> " + exception.InnerException +
"<br /><br /><b>Error Info:</b> " + exception.Message +
"<br /><br /><b>Status Code:</b> " + httpCode +
"<br /><br /><b>Stack trace:</b> " + exception.StackTrace;
string errorInfoDB =
"||Error Location: " + ctx.Request.Url.ToString() +
"||Error Source: " + exception.Source +
"||Error Try/Catch: " + exception.InnerException +
"||Error Info: " + exception.Message +
"||HttpErrorCode: " + httpCode +
"||Stack trace: " + exception.StackTrace +
"||IP Address: " + ipAddress_s;
// clean the input befor you put it in the DB
char quote = (char)34;
char filler = (char)124;
char tick = (char)39;
char greaterThan = (char)60;
char lessThan = (char)62;
errorInfo = errorInfo.Replace(quote, filler);
errorInfo = errorInfo.Replace(tick, filler);
errorInfo = errorInfo.Replace(greaterThan, filler);
errorInfo = errorInfo.Replace(lessThan, filler);
errorInfoDB = errorInfoDB.Replace(quote, filler);
errorInfoDB = errorInfoDB.Replace(tick, filler);
errorInfoDB = errorInfoDB.Replace(greaterThan, filler);
errorInfoDB = errorInfoDB.Replace(lessThan, filler);
string pattern = string.Empty;
string replacement = "sQueEl";
pattern = "/cookie|SELECT|UPDATE|INSERT|INTO|DELETE|FROM|NOT IN|WHERE|TABLE|DROP|script*/ig";
errorInfoDB = Regex.Replace(errorInfoDB, pattern, replacement);
pattern = "/cookie|select|update|insert|into|delete|from|not in|where|table|drop|script*/ig";
errorInfoDB = Regex.Replace(errorInfoDB, pattern, replacement);
if (httpCode == 404)
{
InSert_To_DB_Class(*****, *****, *****, *****, *****, errorInfoDB);
}
else
{
InSert_To_DB_Class(*****, *****, *****, *****, *****, errorInfoDB);
}
// set the error info to the session variable to display to the allowed users
Application["AppError"] = errorInfo;
// clear the error now that is has been stored to a session
ctx.Server.ClearError();
ctx.Response.ClearHeaders();
// set the status code so we can return it for SEO
ctx.Response.StatusCode = httpCode;
ctx.Response.TrySkipIisCustomErrors = true;
HttpApplication myApplication = new HttpApplication();
myApplication.Response.TrySkipIisCustomErrors = true;
try
{
if (ctx.Request.RawUrl.Contains("/*****"))
{
// redirect to the error page
ctx.Server.Transfer("~/*****.aspx", false);
}
else if(ctx.Request.RawUrl.Contains("/*****"))
{
ctx.Server.Transfer("~/*****/*****.aspx", false);
}
else
{
// check the httpCode
if (httpCode == 404)
{
// set the page name they were trying to find to a session variable
// this will be cleared in the ****** page
Application["404_page"] = exception.Message;
// redirect to the 404 page
ctx.Server.Transfer("~/*****", false);
}
else
{
// redirect to the error page
ctx.Server.Transfer("~/*****", false);
}
}
}
}
From this comment to Mr. Disappointment:
Thanks, I'm using IIS 7 local and IIS 7.5 on live. Let me know when you find the material.
If your application is running in an application pool configured to run in Classic Pipeline mode then content not intended for ASP.NET won't hit the ASP.NET runtime. i.e. folders that don't exist. These will be handled directly by IIS.
You have a couple choices:
Set the application pool to Integrated Pipeline mode. You may also need to configure the following setting if IIS's error handling "eats" your ASP.NET 404 and 500 status code from ASP.NET:
<configuration> <system.webServer> <httpErrors existingResponse="PassThrough" /> </system.webServer> </configuration>
If the application is not well behaved in "Integrated Pipeline" mode but you're just concerned about getting a page displayed for a 404 response then configure the following:
<system.webServer> <httpErrors> <remove statusCode="404" subStatusCode="-1" /> <error statusCode="404" prefixLanguageFilePath="" path="/404.aspx" responseMode="ExecuteURL" /> </httpErrors> </system.webServer>
You'd need to set the
404
status code in the page, otherwise it'll just return a200
.If you use a static page, for example:
<error statusCode="404" prefixLanguageFilePath="" path="404.html" responseMode="File" />
This will return a
404
.If the application is not well behaved in "Integrated Pipeline" mode AND you absolutely must pass 404 errors through your error handler then you may have to manually map wildcard content to the ASP.NET HttpHandler so that such requests do hit the pipeline. This would be a sub-optimal solution.
ASP.NET is never being invoked by IIS. IIS handles the page request, sees that the page doesn't exist, and ASP.NET never gets loaded.
If you want ASP.NET to get loaded regardless of whether the file exists, you need to change your IIS configuration. Are you using IIS6 or IIS7/7.5?
You need to set up wildcard mapping so that all requests go through .Net
if your using IIS6 the following link should help you out:
http://professionalaspnet.com/archive/2007/07/27/Configure-IIS-for-Wildcard-Extensions-in-ASP.NET.aspx
Wildcard script mapping and IIS 7 integrated pipeline:
http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/
I can't find the source material for this but I believe the problem lies in the fact it is handling custom error pages and not paths.
You investigation suggests you came across this, inasmuch as:
www.mysite.com/nonexistingpath/nonexistingpage.aspx
This ought to hit the correct error page. The following won't:
www.mysite.com/nonexistingpath/
This kind of reiterates you already answering your own question, but I'll see if I can find the reference material. Ultimately, it isn't a page request, so there is no ISAPI handling through appropriate handlers.
精彩评论