Setting subStatusCode when throwing HttpException for use with httpErrors - asp.net

I am using httpErrors in my web.config and have the following:
<error statusCode="404" subStatusCode="1" responseMode="Redirect" path="http://www.somewhere-else.com" />
Doing the following in a custom action result, works fine:
Response.StatusCode = 404;
Response.SubStatusCode = 1;
But the code that determines whether the 404 redirect is necessary is a bit further down the stack so rather than returning an actionresult, I woul prefer to throw an exception and halt further execution.
For error entries in httpErrors without a subStatusCode, I can throw the appropriate HttpException and it works as expected:
throw new HttpException(400, "Bad Request");
But I need the subStatusCode. I have tried setting Response.SubStatusCode before throwing an HttpException but it gets ignored and the default 404 error page is shown.
Any way around this?
(btw, I know subStatusCode is only internal and not exposed to client)

I realize this question is a bit old, bit figured I'd post an answer that I have come across that seems to work well enough for me. Using Asp.Net MVC 5.2, I throw an HttpException using the following:
throw new HttpException((int) HttpStatusCode.Unauthorized, "Context required", 12)
Then, in my global.asax.cs error handler:
protected void Application_Error()
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
if (httpException != null)
{
Context.Response.StatusCode = httpException.GetHttpCode();
Context.Response.SubStatusCode = httpException.ErrorCode;
Context.Server.ClearError();
}
}
Somewhat hackish, but it suits my needs..

Related

How to redirect to a custom page if maxQueryStringLength exception occured?

How can I replace the standard error page in the case the request length exceeds the one specified in maxQueryStringLength and show the user something more friendly?
Note: Although as an HttpException this falls into generic 400th error, I want to separate the QueryLength condition and show a very specific page for this specific error. So, I cannot use "customErrors" section to indicate a page, but rather need to filter this programmatically. The problem with the below is it doesn't work.
protected virtual void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (logs != null) logs.ExceptionMsg("Application exception", this, ex);
var httpex = ex as System.Web.HttpException;
if (httpex != null && httpex.ErrorCode == -2147467259)
{
Server.ClearError();
Server.TransferRequest(#"~/main/maxlengthexceeded", false);
}
}
The problem is that Server.TransferRequest does not work. Is there an alternative to how I can tell ASP.NET which page to load?
if you are able to catch the error type/number you are getting, then you can configure a different error/redirect page only for that, here an example of configuration in the web.config:
<configuration>
<system.web>
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly">
<error statusCode="500"
redirect="InternalError.htm"/>
</customErrors>
</system.web>
</configuration>
you can see the full article here: Displaying a Custom Error Page

Possible to throw a 404 error within an ASP.Net page?

I was wondering if it's possible to throw a 404 error from within a page(code behind)? Or possibly even throw any other type of error page such as 408(timeout) or 401(authentication required)?
Note: I don't just want to have the page return a status code of 404, I want it to use the ASP.Net(or my CustomErrors) 404 error page.
Something like this in the code behind:
if(id>10){ //if id is greater than 10, then it doesn't exist here
throw 404Error();
}
You could throw an HttpException and set the corresponding status code:
throw new HttpException(404, "Not found");
It will also work with other status codes. Just a remark about the 401: as you probably know when ASP.NET MVC detects this code it automatically redirects you to the login page and getting a custom error page for the 401 status code could be a real PITA to implement.
A much better way is:
// Throws a 404 Not found
Response.Clear();
Response.StatusCode = 404;
Response.End();
There is no need to throw an exception and the above works much better when using custom error pages in the Web.Config
In regards of Page Load in ASP.NET WebForms needs some small workaround.
protected void Page_Load(object sender, EventArgs e)
{
HttpNotFound();
}
private void HttpNotFound()
{
Response.Clear();
Response.StatusCode = 404;
Response.End();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
If your client is capable of hitting the PHP page so code is executed, it means that you didn't get a 404 (client side error, "path/file not found"), nor did you get any other sort of 400-class error, BUT you are instead actually getting what should be classified as a 500 error of some sort.
The HTTP spec uses file/path as synonyms. This comes from the old days of the internet when it was super common for webservers to expose directory browsing lists.

In ASP.NET how to identify/process 404 exceptions?

I need to handle 404 exceptions differently than all other types of them. What is the best way to identify those 404 exceptions (distinguish them from other exceptions)?
The problem is that there is no a special exception class for 404 errors, I get regular System.Web.HttpException with Message = "File does not exist."
Should I just use exception's message for it or is there a better way?
Thank you.
You can try to cast the exception as an HttpException, and then use the GetHttpCode method to check whether it is a 404 or not.
For example:
Exception ex = Server.GetLastError();
HttpException httpEx = ex as HttpException;
if (httpEx != null && httpEx.GetHttpCode() == 404)
{
//do what you want for 404 errors
}
I'd suggest that you configure your application to redirect 404 errors to a specific page, such as ~/FourOhFour.aspx. In this page you can inspect the aspxerrorpath querystring parameter, which will report the page the user was attempting to visit. From here you can do all sorts of interesting things, from logging the 404, to emailing yourself a message, to trying to determine the correct URL and auto-redirecting the user to that.
To configure your web application to redirect the user to a custom page in the face of a 404, add the following markup to web.config in the <system.web> section:
<customErrors mode="On" defaultRedirect="~/GeneralError.aspx">
<error statusCode="404" redirect="~/FourOhFour.aspx" />
</customErrors>
For more information, see:
<customErrors> element documentation
You can catch the exception. You're trying to catch this in a client application, correct?
HttpWebRequest req = ( HttpWebRequest )WebRequest.Create( someURL );
try
{
HttpWebResponse resp = req.GetResponse();
}
catch( WebException webEx )
{
if( webEx.Response != null )
{
HttpWebResponse response = webEx.Response as HttpWebResponse;
switch( response.StatusCode )
{
case HttpStatusCode.NotFound:
// do something
break;
In the Web.Config file you can specifiy a seperate File for each error code.
<customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">
<error statusCode="404" redirect="FileNotFound.aspx" />
</customErrors>

Convert an exception into HTTP 404 response in the Application_Error

First of all, quickly what exactly I want to achieve: translate particular exception into the HTTP 404 so the ASP.NET can handle it further.
I am handling exceptions in the ASP.NET (MVC2) this way:
protected void Application_Error(object sender, EventArgs e) {
var err = Server.GetLastError();
if (err == null)
return;
err = err.GetBaseException();
var noObject = err as ObjectNotFoundException;
if (noObject != null)
HandleObjectNotFound();
var handled = noObject != null;
if (!handled)
Logger.Fatal("Unhandled exception has occured in application.", err);
}
private void HandleObjectNotFound() {
Server.ClearError();
Response.Clear();
// new HttpExcepton(404, "Not Found"); // Throw or not to throw?
Response.StatusCode = 404;
Response.StatusDescription = "Not Found";
Response.StatusDescription = "Not Found";
Response.Write("The whole HTML body explaining whata 404 is??");
}
The problem is that I cannot configure default customErrors to work with it. When it is on then it never redirects to the page specified in customErrors: <error statusCode="404" redirect="404.html"/>.
I also tried to raise new HttpExcepton(404, "Not Found") from the handler but then the response code is 200 which I don't understand why.
So the questions are:
What is the proper way of translating AnException into HTTP 404 response?
How does customErrors section work when handling exceptions in Application_Error?
Why throwing HttpException(404) renders (blank) page with success (200) status?
Thanks,
Dmitriy.
In a few words, you if you manually set HTTP status in Application_Error, you lose possibility to use customErrors section handler, since you call Server.ClearError().
Handle the exception before Application_Error or derive the exception from HttpException.
What is the proper way of translating AnException into HTTP 404 response?
It's better to handle exceptions in Controller. You can introduce base class controller and handle most of exceptions in custom HandleError attribute. You can throw HttpException their and it will be properly handled by customErrors section handler.
You can also derive your ObjectNotFoundException exception from HttpException(404)
Application_Error is the last chance to handle an exception. You have only Response API to handle it. You can manually set status code and write to response or manually trigger redirect to custom error page or call Server.TransferRequest() to existing html or aspx file (not to the controller action). In current asp.net version, you cannot set or change Server.GetLastError in Application_Error method only retrieve or clear it.
How does customErrors section work when handling exceptions in Application_Error?
By calling Server.ClearError() you also clean current request error therefore it is not handled by customErrors section handler
Why throwing HttpException(404) renders (blank) page with success (200) status?
You should no throw any exception in Application_Error method. Exception means that your error handling failed.

404 page response.redirect vs server.transfer

when handling 404 errors in ASP.NET is it ok to set 404 errors to redirect to a page that sends the 404 response code to the browser or should server.transfer be used so the 404 header can be sent to the browser while the url remains the same?
customErrors statusCode="404" results in a 302 temporary redirect then a 404 (if you've set that in your 404 page's code).
Therefore, the following should do it for you in your global.asax or error HttpModule:
protected void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
if (exception is HttpUnhandledException)
{
if (exception.InnerException == null)
{
Server.Transfer(ERROR_PAGE_LOCATION, false);
return;
}
exception = exception.InnerException;
}
if (exception is HttpException)
{
if (((HttpException)exception).GetHttpCode() == 404)
{
Server.ClearError();
Server.Transfer(NOT_FOUND_PAGE_LOCATION);
return;
}
}
if (Context != null && Context.IsCustomErrorEnabled)
Server.Transfer(ERROR_PAGE_LOCATION, false);
else
Log.Error("Unhandled exception trapped in Global.asax", exception);
}
Edit: Oh, and Best way to implement a 404 in ASP.NET put me on the road to the imperative Server.ClearError();
See http://www.andornot.com/blog/post/Handling-404-errors-with-ASPNET.aspx for a post I did that covers all of this.
I would use the customerrors section of the web.config, then you can specify the page you want 404 to go to.
<configuration>
<system.web>
<customErrors mode="On" defaultRedirect="Error.aspx">
<error statusCode="404" redirect="404Error.aspx" />
</customErrors>
</system.web>
</configuration>
On the receiving page if you want to still send the 404 you can place this in the page_load event:
Response.Status = "404 Not Found";
Response.Redirect will do 302 first than 404 on redirected page.
Server.Transfer will keep the URL, so it is 404 on requested page.
I think it all comes down SEO. I suggest using Server.Transfer as it is more clear to browser/search engine that the requested URL is not found. If you use Response.Redirect requested page is 'temporarily' redirected to a not found page. That's not good... 302 is not a good idea.
My advice is to let the ASP.NET process do the work for you based on your web.config but if you really want to to this in code you should stick with Server.Transfer cause it will save you a postback.

Resources