Application_Error no longer triggers when published to IIS - c#

OK I have the following code in my Global.asax file:
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Exception objError = Server.GetLastError().GetBaseException();
Response.Redirect(
String.Format(
"/Error/{0}/{1}",
((HttpException)objError).GetHttpCode(),
Request.RawUrl));
}
To provide neat and tidy error urls like "/Error/404/TheNameOfTheRequestedPage". This works fine from VS 2008, but once published to my local machine, I get the default error page:
Error Summary
HTTP Error 404.0 - Not Found
The resource you are looking for has
been removed, had its name changed, or
is temporarily unavailable
Anyone know how to do this? I've chosen not to use system.web/customErrors because I don't have access to Server.GetLastError() from there (or at least it's never worked for me) and I want to get the http code.

This is most likely related to you triggering an IIS Http Error which is defined in the web.config under the nodes
<system.webServer>
<httpErrors>
</httpErrors>
<system.webServer>
If the issue is you're returning an a response code for 404 and getting the IIS 404 page the issue is you need to do
Response.TrySkipIisCustomErrors = true;
Before you let the response finish otherwise IIS will intercept the error.
This is completely beyond unintuitive especially if you set the status code yourself. I tried to figure a way to file a bug on Microsoft Connect that manually setting a http error code does not automatically set TrySkipIisCustomErrors but could not seem to figure out any relevant product to submit it to.

I had a similar problem, and a call to Server.ClearError() before the redirect did solve the problem.
In your case I would write
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Exception objError = Server.GetLastError();
if(objError is HttpException){
//Need to clear the error, otherwise the buil-in redirect would occure
Server.ClearError();
Response.Redirect(
String.Format(
"/Error/{0}/{1}",
((HttpException)objError).GetHttpCode(),
Request.RawUrl));
}
}
Notice that Server.GetLastError().GetBaseException() returns the base exception, which isn't always the HttpException, the one you are looking for is just GetLastError().

Related

Post method receives null when sending an object with a memory size greater than 30MiB

so the first thing i do with my application is have the user select an excel file. I then take that file and send it to the server to parse the file and then i return an object with all the rows. This works fine. (the file really only contains numbers and strings nothing complex)
Next the user will select a few more things to modify the object (these only change lookup ids on the object)
finally the users goes to submit this object to be saved. Normally this works fine, but as I was testing I found that all of a sudden it kept erroing out. So I investigated and found that it was sending null to the api but the object in angular was still alive and well.
I continued to investigate and found that it had to do with the memory size of the object. (atleast I believe that to be the case). I found that as my object is greater than 33.740 MiB the api only recieves a null object instead of the correct object it had no problem receiving earlier.
A large part of the object size is almost exclusively related to the file size the user selects to upload.
Does anyone know if there is a limit that an api will have when sending to an api. Is there a setting im missing on my post? Additionaly does anyone know how to possible debug this issue because I am kinda at a lost as what exactly to do next. Besides putting a file size limitation for the user to see. I dont expect object or file sizes to get near 4GiB but 100sMiB is possible.
I know google has a limit of 4GiB but im not hitting that. examples of code below. let me know if you need more information.
Post Method
[Authorize]
[HttpPost]
[Route("TempRoute")]
public IHttpActionResult PostTempRoute(Object1 InObject)
{//InObject is null so it errors on the if statement inside the try catch
try
{
if(InObject.Prop1== null || InObject.Prop1.Count==0)
{
return GetResult(InObject);
}
else
{
ObjectService.GetObjects(InObject,this.User.Identity.Name);
return GetResult(InObject);
}
}
catch(Exception e)
{
ErrorLogService.SaveErrorLog(e, this.User.Identity.Name);
return InternalServerError();
}
}
Basically the solution is this. (Unfortunately this is for IIS only as I do not know some of the more common webhosting solutions.)
In your webconfig add the lines below to your webconfig. Both lines are important however, as one changes it for your codebehind the other changes it for IIS. They MUST match. To read more about this see here. Essentially this is a requestLimits feature that has a default and you override by using the following code in your webconfig.
Please note the First is in Kilobytes the Second is in bytes.
<system.web>
<httpRuntime maxRequestLength="1074000" executionTimeout="3600" />
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1074000000" />
</requestFiltering>
</security>
</system.webServer>
In addition if you are wishing to know how to debug this. in your api that is receiving null there should be a Request.Content variable available. hover over and exam it. As you go down into the object and properties you will find there is an error and that error will be along the lines of Max length exceeded.
In global.ascx I have added a catch to log that error.
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
var httpException = ex as HttpException ?? ex.InnerException as
HttpException;
if (httpException == null) return;
if(((System.Web.HttpException)httpException.InnerException).WebEventCode
== System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
{
//handle the error
Response.Write("Too big a file, dude"); //for example
}
}

I am not being able to see a detailed output of a server error?

In asp.net, i can't see the detailed message of the server when an error is present. I mean, when you open a browser and navigate to say http://[errorpage].com and the page shows something like "internal server error - the server is busy" - surely you know that the server is busy...but with my application i get only error 503 - but i cant go as far as mozilla browser goes and cannot see the entire error message. I tried to catch and display the exception - but...no. also i tried to parse the source with regular exp. - but i guess net stops whenever error is present and cannot proceed to parsing - also...without trycatching: same thing.
As a rule, don't enable this on live websites. In your web.config, add/edit the following:
<customErrors mode="Off" />
This will start showing detailed info about the error. But again, DO NOT do this on a live server, or at least not permanently, as it is a security hazard.
The best way to do that is to implement error handling into your code, then save errors somewhere (database, file ...) Then you can look into your file and get a full error
e.g.
try {
//your code here
}
catch(Exception ex)
{
//write to file ex.ToString() to see whole stack trace, or ex.Message to see just message like "index out of bounds"
}
and also if you want to get errors in browser then turn it on in your config file
look at this link for details http://msdn.microsoft.com/en-us/library/h0hfz6fc.aspx
Your question is a little manic, but you've got to consider what error handling is going on up the stack if this is happening:
try{
//Something
}
catch(Exception){
//Handle it some how
throw new Exception("Broken");
}
then this will loose all of the call stack before the new exception is thrown. If this is happening it can be fixed like this:
try{
//Something
}
catch(Exception){
//Handle it some how
throw;
}
this continues to throw the original exception with stack trace.
If you turn on ASP.NET Health Monitoring, then ASP.NET will log details of the error to the Windows Event Log or any other destination you specify.

How to handle PrincipalPermission Security exceptions

I have a simple method that is secured
[PrincipalPermission(SecurityAction.Demand, Role = "Administrator")]
protected void lnkClearCache_Click(object sender, EventArgs e)
{
...
}
If this is clicked without the role, it generates a System.Security.SecurityException: Request for principal permission failed. as expected.
I use ELMAH to handle logging for my errors, and I have a custom ELMAH event in my global.asax to transfer to the error pages in ways that preserve status codes which works correctly.
private void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
{
var customErrorsSection = GetCustomErrorsSection();
var error = args.Entry;
string statusCode = error.Error.StatusCode.ToString();
if (statusCode == "0" && error is security exception)
statusCode = "403";
var errorSection = customErrorsSection.Errors[statusCode];
string redirectUrl = errorSection == null ?
customErrorsSection.DefaultRedirect : errorSection.Redirect;
RespondWithServerError(error.Id, redirectUrl, statusCode);
}
This works all well and fine and redirects to my error page which works properly, however instead of displaying the content as expected. I immediately get a second request for the error page but this time using the value of customErrorsSection.DefaultRedirect that does not come from my code in any way that I can see.
As far as I can tell it's almost as if when .NET raises an exception for PrincipalPermission and then lets the entire request complete, then after the request is complete it throws away the application response and instead responds with the default custom error.
When I'm debugging I do break on 2 separate exceptions for PrincipalPermission, whether this is a just a rethrow by .NET I'm not sure but my .NET code never sees the 2nd throw, nor does ELMAH. I always end up with a single response, single error logged, but that the url that finally renders to the browser is the default url and not 403 url that I specifically server.transferred to. If I browse to a /location that is secure I properly get the 403 error page.
I don´t excactly know where the problem is. But i´´m using something similar and for me this solution (minimized) works great.
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
Dim er = HttpContext.Current.Error
If er.GetType.Equals(GetType(System.Security.SecurityException)) Then
HttpContext.Current.Response.Redirect(FormsAuthentication.LoginUrl & "?ReturnUrl=" & HttpContext.Current.Request.Path)
End If
End Sub
That´s out of global.asax
But on some places I don´´t redirect, and just using try and catch the securityexception to display the user, that he is not allowed to perform such action.

How to catch ConfigurationErrorsException for violating maxRequestLength?

I am limiting file size users can upload to the site from Web.config. As explained here, it should throw a ConfigurationErrorsException if size is not accepted. I tried to catch it from the action method or controller for upload requests but no luck. Connection is resetted and I can't get it to show an error page.
I tried catching it in BeginRequest event but no matter what I do the exception is unhandled.
Here's the code:
protected void Application_BeginRequest(Object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
try
{
if (context.Request.ContentLength > maxRequestLength)
{
IServiceProvider provider = (IServiceProvider)context;
HttpWorkerRequest workerRequest = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
// Check if body contains data
if (workerRequest.HasEntityBody())
{
// get the total body length
int requestLength = workerRequest.GetTotalEntityBodyLength();
// Get the initial bytes loaded
int initialBytes = 0;
if (workerRequest.GetPreloadedEntityBody() != null)
initialBytes = workerRequest.GetPreloadedEntityBody().Length;
if (!workerRequest.IsEntireEntityBodyIsPreloaded())
{
byte[] buffer = new byte[512];
// Set the received bytes to initial bytes before start reading
int receivedBytes = initialBytes;
while (requestLength - receivedBytes >= initialBytes)
{
// Read another set of bytes
initialBytes = workerRequest.ReadEntityBody(buffer, buffer.Length);
// Update the received bytes
receivedBytes += initialBytes;
}
initialBytes = workerRequest.ReadEntityBody(buffer, requestLength - receivedBytes);
}
}
}
}
catch(HttpException)
{
context.Response.Redirect(this.Request.Url.LocalPath + "?action=exception");
}
}
But I still get this:
Maximum request length exceeded.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Maximum request length exceeded.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Update:
What method raises the exception anyway? If I read the request it raises exception If I don't read it at all, I get "101 Connection Reset" in browser. What can be done here?
You cant catch error in action method becouse exception comes earlier, but you can catch it here
protected void Application_Error() {
var lastError = Server.GetLastError();
if(lastError !=null && lastError is HttpException && lastError.Message.Contains("exceed")) {
Response.Redirect("~/errors/RequestLengthExceeded");
}
}
Actualy when file size exceeds limits HttpException error arise.
There is also IIS limit on content - wich can't be catched in application. IIS 7 throws
HTTP Error 404.13 - Not Found The
request filtering module is configured
to deny a request that exceeds the
request content length.
You can google it, there is a lot of information about this iis error.
There is no way to do it right without a client-side help. You cannot determine if the request is too long unless you read all of it. If you read each request to the end, anyone come and keep your server busy. If you just look at content length and drop the request, other side is going to think there is a connection problem. It's nothing you can do with error handling, it's a shortcoming of HTTP.
You can use Flash or Javascript components to make it right because this thing can't fail nicely.
I am not 100% on this, but I think it might help if you tried changing:
context.Response.Redirect(this.Request.Url.LocalPath + "?action=exception");
to
Server.Transfer(this.Request.Url.LocalPath + "?action=exception,false)
My thinking is that the the over-max-request-length Request is still being processed in the Redirect call but if you tell it to ditch the form data, it will become under the max request length and then it might behave differently.
No guarantees, but its easy to check.
catch (Exception ex)
{
if (ex is HttpException && (ex as HttpException).WebEventCode == 3004)
{
//-- you can now inform the client that file uploaded was too large.
}
else
throw;
}
I have a similar issue in that I want to catch the 'Maximum request length exceeded' exception within the Application_Error handler and then do a Redirect.
(The difference is that I am writing a REST service with ASP.Net Web API and instead of redirecting to an error page, I wanted to redirect to an Error controller which would then return the appropriate response).
However, what I found was that when running the application through the ASP.Net Development Server, the Response.Redirect didn't seem to be working. Fiddler would state "ReadResponse() failed: The server did not return a response for this request."
My client (Advanced REST Client for Chrome) would simply show "0 NO RESPONSE".
If I then ran the application via a local copy of IIS on my development machine then the redirect would work correctly!
I'm not sure i can definitively say that Response.Redirect does not work on the ASP.Net Development Server but it certainly wasn't working in my situation.
So, I recommend trying to run your application through IIS instead of IIS Express or the Development Server and see if you get a different result.
See this link on how to Specify the Web Server for Web Projects in Visual Studio:
http://msdn.microsoft.com/en-us/library/ms178108(v=vs.100).aspx

Redirect to error page

I want to use Response.Redirect to redirect the browser when an exception occurs.
I also want to pass the exception message to my error page.
For example:
string URL = "Page2.aspx?Exception=" + ex.ToString()
Response.Redirect(URL)
Can it be done? Is this the right syntax?
Instead of Response.Redirect, which sends a response to the client asking it to request a different page, you should call Server.Transfer, which runs a different page immediately and sends that page directly to the client.
You can then put the exception in HttpContext.Items and read it from HttpContext.Items in your error page.
For example:
catch (Exception ex) {
HttpContext.Current.Items.Add("Exception", ex);
Server.Transfer("Error.aspx");
}
In Error.aspx, you can then get the exception like this:
<%
Exception error;
if (!HttpContext.Current.Items.Contains("Exception"))
Response.Redirect("/"); //There was no error; the user typed Error.aspx into the browser
error = (Exception)HttpContext.Current.Items["Exception"];
%>
Yes that would work (with some semicolons added of course and you probably just want to send the exception message):
String URL = "Page2.aspx?Exception=" + ex.Message;
Response.Redirect(URL);
As Andrew said, it should work.
However, if you're looking for Error Management, you're better off using Server.GetLastError() so you get the full Exception object including stack trace.
Here's an MSDN article that deals with Application Errors in general and uses Server.GetLastError().
Typically I would have panels in my page and toggle visibility in the catch block to display a friendly message to the user. I would also include an emailed report to myself detailing the error message.
try
{
}
catch (Exception ex)
{
formPanel.Visible = false;
errorPanel.Visible = true;
// Log error
LogError(ex);
}
As for reporting/forwarding the error to another page:
string errorURL = "ErrorPage.aspx?message=" + ex.Message;
Response.Redirect(errorURL, true);
And don't forget ELMAH!
http://bit.ly/HsnFh
We would always advise against redirecting to a .aspx page on an error condition.
In the past we've seen scenarios where a fundamental issue with the application has caused an error to occur, which has in turn redirected to an error.aspx page, which it's self has errored resulted in an endless redirection loop.
We strongly advise people to use a .htm page or something which is not handled by the ASP.NET framework for error pages.
There is built in support within ASP.NET using the customErrors section of the Web.config to automatically handle error redirection for you.
customError tag
You can look into global exception handling too, this can be managed via the Application_OnError event which you can find within the global.asax
Thanks,
Phil
http://exceptioneer.com

Categories

Resources