I have the following code in my Global.asax file:
protected void Application_Error()
{
var exception = Server.GetLastError();
Response.Clear();
Server.ClearError();
//processing
Response.RedirectPermanent("url processed"));
}
At localhost this works fine, doing something like this:
I access to "www.somesite.com/uk/en-GB", and because this route isn't registered the Application_Error "catch" the error, process it and redirect to the correct route "www.somesite.com/en-GB". (As shown in the code above at Global.asax)
But at the server, I try to access to "www.somesite.com/uk/en-GB", and it don't goes to Application_Error, instead of that show me this error:
Anyone know how to solve this?
You didn't get an error. You got a 404 response code. You'll need to handle that scenario differently. The Application_Error only catches uncaught exceptions.
I'm running IIS 6 and I found that this problem was easily fixed with adding this to my Web.Config file under system.web:
<customErrors mode="Off">
</customErrors>
This will allow the code in Application_Error to execute.
Related
I've currently got httpErrors setup to deal with 500's here:-
<httpErrors errorMode="Custom" existingResponse="Replace">
......
<remove statusCode="500"/>
<error statusCode="500" path="/server-error" responseMode="ExecuteURL"/>
</httpErrors>
This works fine, but in the case where iis receives the error I still get the yellow screen of death. An example is when entity framework can not connect to the database and I receive:-
Cannot open database "Test-DB" requested by the login. The login failed. Login failed for user 'sa'.
I've setup customErrors to deal with this:-
<customErrors mode="On" defaultRedirect="error.html" redirectMode="ResponseRedirect">
<error statusCode="500" redirect="error.html" />
</customErrors>
which works as expected as long as there is no modules without preCondition="managedHandler".
I have a few modules which deal with images and css files and are in the same project.
<modules runAllManagedModulesForAllRequests="false">
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
<add name="ImageHandler" type="foo.bar.ProductImageHandlerHttpModule" />
<add name="CustomCssHandler" type="foo.bar.CustomCssHttpModule" />
<add name="Glimpse" type="Glimpse.AspNet.HttpModule, Glimpse.AspNet" preCondition="integratedMode" />
</modules>
Comment these out and I get the error.html, keep them in and I get
Runtime Error Description: An exception occurred while processing your
request. Additionally, another exception occurred while executing the
custom error page for the first exception. The request has been
terminated.
showing that a module from the project is also erroring when trying to show the error.html.
Does anyone know a fix/workaround?
Its a tough situation - your error comes from HttpModule, which is run for every single request - including request to error.html page. One way is to route static files (such as error.html) just via your server - and ignore them on .NET level; this may not be always possible (sometimes handling static files on .NET level is handy). The only other way I can think off is hook in global.asax to error event and handle it yourself (which will ignore the customErrors)
Something like:
public class Global : System.Web.HttpApplication
{
protected void Application_Error(object sender, EventArgs e)
{
// is there an error ?
var error = Server.GetLastError();
if (error != null)
{
// mark the error as - "i'll handle it myself"
Server.ClearError();
// load error.html manually & dump it to response
var content = File.ReadAllText(Server.MapPath("~/error.html"));
Context.Response.Write(content);
// set correct error code
Context.Response.StatusCode = 500;
}
}
}
Note: this can be ironed out, but you see the general principle ...
As #Ondrej said, another error occurred when handling the custom error page comes from unhandled exception on HttpModule, thus it is necessary to either skip or bypassing customErrors section on web.config file.
This code also includes how to skip custom errors generated from IIS, besides generating custom HTML error page:
protected void Application_Error(Object sender, EventArgs e)
{
// Get last error occurred
var exception = Server.GetLastError();
// catch unhandled exceptions
if (exception is HttpUnhandledException)
{
// handle the error by ASP .NET itself
Server.ClearError();
// write status code handling
HttpContext.Current.Response.WriteFile(Server.MapPath("~/error.html"));
HttpContext.Current.Response.StatusCode = 500;
HttpContext.Current.Response.StatusDescription = "Internal Server Error";
// set ASP .NET handlers instead of using IIS handlers
HttpContext.Current.Response.TrySkipIisCustomErrors = true;
}
}
Additionally, to get rid of YSOD pages generated by IIS you may set existingResponse attribute to pass error handling into ASP .NET Application_Error method as this:
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="PassThrough">
<remove statusCode="500" />
<error statusCode="500" responseMode="File" path="/error.html" />
</httpErrors>
</system.webServer>
The reason behind those settings based from Kanwaljeet Singla's explanation (source here):
existingResponse
Value of this section level property tells custom error module what to
do when response text is not blank. If a module call
IHttpResponse::SetStatus to set an error code and also sets up
response text, existingResponse property tells if custom error module
should replace current response text with its own error text or should
it let the current response text pass through. Asp.Net and WCF are
example of modules which sets error response text. This property can
be set to following three values.
Replace – This value make custom error module to always replace the error information with text generated by custom error module. If
existingResponse is set to “Replace”, errors/exceptions generated by
Asp.Net/WCF are replaced by IIS7 errors.
PassThrough – If existingResponse is seen as “PassThrough”, custom error module will always pass through responses from modules.
This setting will make custom error module return blank response if
modules don’t set any text.
Auto – This is the default value and tells custom error module to do the right thing. Actual error text seen by clients will be
affected depending on value of fTrySkipCustomErrors returned in
IHttpResponse::GetStatus call. When TrySkipCustomErrors is set to
true, custom error module will let the response pass through but if it
is set to false, custom errors module replaces text with its own text.
Asp.Net/WCF call IHttpResponse::SetStatus with TrySkipCustomErrors
true so that IIS doesn’t override their errors with its own. When
effective errorMode is “Detailed” and response is non-empty, this
value of existingResponse will act as “PassThrough” regardless of
value of TrySkipCustomErrors.
Hopefully this may figure out the essential things when setting custom error page for unhandled exception responses.
MSDN References:
https://msdn.microsoft.com/en-us/library/ms690576(v=vs.90).aspx
https://msdn.microsoft.com/en-us/library/system.web.httpresponse.tryskipiiscustomerrors(v=vs.110).aspx
SO References:
IIS7 Overrides customErrors when setting Response.StatusCode?
How to send status code "500" for generic error page in IIS?
Getting IIS7 'one liner' error when using custom error settings in web.config
It seems if your iis is set with Integrated Mode then Modules will still be run for static files. If you set it to Classic mode it will ignore the managed modules for static files.
Please refer this thread for more infomration see the answer of João Angelo Requests for static files are hitting the managed code in ASP.NET MVC3
The fix is either you changed your handler to not throw exception or you change iis to classic mode so if any handler or other part throws exception and iis redirects to error.html then none of manage module should hit.
For error handling, I have added the following code to Web.config:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error.cshtml?">
</customErrors>
<system.web>
And in Global.asax.cs:
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Response.Redirect("/Error.cshtml?");
}
However, when the redirect to /Error.cshtml? occurs, there is an error 'This page has a redirect loop'
I've searched through other similar questions (such as How to solve Redirect Loop). However, I have no other routes calling Error.cshtml -- so does anyone have any idea what is causing this loop and how I can work around it?
EDIT: There are multiple errors occurring, and therefore the error page redirect is involved in a redirect loop. Does anyone know of a way to only call Response.Redirect("~/Error.cshtml") once?
EDIT2: If I change the redirect url to a random url outside of the project (such as https://www.facebook.com/), the customError redirect works properly. Still looking for a way to redirect to project page without infinitely looping through the error
Try adding:
Server.ClearError();
first to clear the existing error before redirecting.
Add redirectMode="ResponseRewrite" to customErrors section.
In my global I have the following code to handle when an error occurs
//[..] code goes here
Server.Transfer("~/Error.aspx?ErrorID=" + errorId);
It used to be a Response.Redirect which worked perfectly except that it changed the url (which is why I want to use Server.Transfer)
Unfortunately, now when it tries to load the Error page, it crashes on the Masterpage when it tries to refer to the Session
HttpException:
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 \\
section in the application configuration.
I do have enableSessionState in both my config and my page.
I also found some links which suggest using Context.RewritePath - that just causes a blank page to load for me.
Using Response.Redirect works perfectly and as expected, so I assume Server.Transfer is the issue here. What is it?
EDIT Code:
protected void Application_Error(object sender, EventArgs e)
{
lock (_lockMe)
{
Exception ex = Server.GetLastError();
if (ex != null)
{
if (ex.InnerException != null)
ex = ex.InnerException;
ErrorLoggingManager.AddError(ex, new MembershipData(), ...); //etc
}
Server.ClearError();
//Some other database code for cleaning up some stuff when an error happens
}
try
{
if (Response != null)
{
//Get the last error logged
MyDataContext db = new MyDataContext();
int errorId = db.LoggedErrors.OrderByDescending(le => le.ErrorId).Select(le => le.ErrorId).FirstOrDefault();
Server.Transfer("~/Error.aspx?ErrorID=" + errorId);
}
}
catch (Exception)
{
}
}
As you have not posted much code. So without seeing the actual implementation you have done. I could suggest you below points.
Point 1. First of all, you need to check if SessionState is enabled for pages. You could set them globally in web.config file. Try the snippet given below in web.config
<configuration>
<system.web>
<pages enableSessionState="true" />
</system.web>
</configuration>
Point 2. And put your Redirection in Application_Error in Global.asax.
public void Application_Error(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
app.Server.Transfer("~/Error.aspx?ErrorID=" + errorId,true);
}
Point 3. Also check if your SessionStateis set properly in IIS too.
Details are on MSDN to enable sessionstate
Hope this helps..!!!
From what I understand, Server.Transfer sends the content of another page to the client rather than the requested content. If that is the case, then I am wondering if it does not have something to do with applying a master page to the error page? I had a similar error years ago with earlier technology and it turned out that the master page did not like what I was trying to do.
I hope this helps at least point to a solution.
Here's what the problem is:
If there is a page render exception (ex. "File Not Found") then Server.Transfer screws up the session. This has something to do with it being called during the page render.
As long as you are not appending headers before the error occurs, Response.Redirect will work just fine; if you are, however, using Response.AppendHeader then Response.Redirect will not work during a page render.
Try using HttpContext.Current.RewritePath instead. That should fix all these problems. For whatever reason, RewritePath() does not care that the page hasn't finished rendering.
why not just use customErrors in web.config to do the redirect?
<customErrors mode="Off" defaultRedirect="~/Common/Error.aspx">
<error statusCode="403" redirect="~/SM_AccessDenied.aspx" />
<error statusCode="404" redirect="~/Common/FileNotFound.aspx" />
</customErrors>
I had the same problem in a different context a while ago. I don't know if it is your case, but if you're using IIS7 on Windows 2008, in addition to setting enableSessionState=true in your web.config, you have to put your modules inside the <system.webServer> section, instead of <system.web>. Changing this little thing solved it for me.
Why don't you try like this:
The Server.Transfer method also has a second parameter—"preserveForm". If you set this to True, using a statement such as Server.Transfer("WebForm2.aspx", True), the existing query string and any form variables will still be available to the page you are transferring to.
So I think doing like this your session will not expire.
Server.Transfer("~/Error.aspx?ErrorID=" + errorId,True);
The error you are encountering is because you are using a query string parameter. Per the msdn docs
However, the path parameter must not contain a query string, or ASP returns an error.
http://msdn.microsoft.com/en-us/library/ms525800%28v=vs.90%29.aspx
Its about 3/4 of the way down the page just above Requirements.
Even though the docs here are mentioning asp. and not asp.net, keep in mind the session state is a feature of IIS and is handled before asp.net is ever called.
#user2110845 : I had faced similar problem few months ago. the problem was with having an underscore in the website name. We were deploying a website in IIS with two different host names(adding two entries through the 'Edit Bindings' option on the website). The host names provided were abc_ts, abc_is. When the underscore was removed then the session problem got resolved.
It seems there are certain characters not allowed in a website host name. Check if that is your problem.
I found the answer here : link (check 'update 2' in the article)
You don't mention what version of ASP.NET you are using, but there were some changes between 2.0 and 3.5 in how unhandled exceptions bubbled their way up through an ASP.NET web app and then IIS.
Among some other possibles, while you are clearing the error you are not setting Context.Response.TrySkipIisCustomErrors = true; While this particular flag could have nothing to do with your issue (and is only available for 3.5+), it also could help deal with what is potentially two error pages behind the scenes that are obscuring the real issue. Regardless, it'll save you a lot of grief (at least if you are running 3.5+) with other potential issues. Check out two posts I wrote several years back that may be helpful: while they don't cover session handling, they do cover the multiple song-and-dance routines I had to follow to get proper 500 and 404 handling in various versions of ASP.NET. It's possible you will run into something that will get you further ahead, if not all the way there.
http://www.andornot.com/blog/post/Errors-Sending-the-Right-Message-(Redux-Covering-ASPNET-3540).aspx
http://www.andornot.com/blog/post/Errors-Sending-the-Right-Message.aspx
In asp.net, I can define a custom error page like this:
<configuration>
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="/servererrors/404.aspx" />
</customErrors>
</system.web>
</configuration>
Now my question: If I replace, say 404.aspx with AnyHTTP.aspx,
and want to get the number of the http error to generalize the page, how do I get that error numer?
Try this setting in CustomErrors (ASP.NET 3.5 SP1):
<customErrors mode="RemoteOnly" defaultRedirect="/servererrors/AnyHTTP.aspx" RedirectMode="ResponseRewrite"/>
As a different solution, you can also do this in Global.asax:
void Application_Error(object sender, EventArgs e)
{
Server.Transfer("/servererrors/AnyHTTP.aspx");
}
and on your error page, load the last error:
Exception e = Server.GetLastError();
It is important to use Server.Transfer() in the Global.asax file; using Response.Redirect will throw a 302 error and you will lose the error that you wanted to catch.
Well you might take a look at http://www.raboof.com/projects/Elmah/ before you venture to deep into doing your own thing...
I'd recommend not using the web.config method. customErrors redirects to the error page, which makes little sense. Essentially it first says "oh yes, that'll work perfectly, you just need to go here instead", and then says "oh, we didn't find that". That's really a bug (if there isn't anything here, then why did the server tell me to go here, clearly to the user code it looks like you the server code messed up; they went to the right URI and then you directed them to the wrong one).
Use Server.Transfer() from global.asax, set a default HTTPHandler, or set IIS to execute (not redirect to) your .aspx or other file with your implementation. If you want the same handler to manage each error, then you could, for example, do a Server.Transfer() from global.asax, but include a query string parameter about the type of error (whether simply an HTTP status code, or something more detailed), or pass information in the HttpContext.
Coming from a desktop background I'm not sure exactly how to pass the exceptions I have caught to an Error page in order to avoid the standard exception screen being seen by my users.
My general question is how do I pass the exception from page X to my Error page in ASP.net?
I suggest using the customErrors section in the web.config:
<customErrors mode="RemoteOnly" defaultRedirect="/error.html">
<error statusCode="403" redirect="/accessdenied.html" />
<error statusCode="404" redirect="/pagenotfound.html" />
</customErrors>
And then using ELMAH to email and/or log the error.
The pattern I use is to log the error in a try/catch block (using log4net), then do a response.redirect to a simple error page. This assumes you don't need to show any error details.
If you need the exception details on a separate page, you might want to look at Server.GetLastError. I use that in global.asax (in the Application_Error event) to log unhandled exceptions and redirect to an error page.
We've had good luck capturing exceptions in the Global.asax Application_Error event, storing them in session, and redirecting to our error page. Alternately you could encode the error message and pass it to the error page in the querystring.
You can also get the exception from
Server.GetLastError();
Use the custom error pages in asp.net, you can find it in the customError section in the web.config
We capture the exception in the Global.asax file, store it in Session, the user is then redirected to the Error Page where we grab the exception for our Session variable and display the Message information to the user.
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
this.Session[CacheProvider.ToCacheKey(CacheKeys.LastError)] = ex;
}
We do log the error message prior to displaying it the user.
I think you can use the global.asax -- Application_Exception handler to catch the exception and then store it for displaying in an error page.
But actually, your error page shouldn't contains code that might cause just another error. It should be simple "Oops! something went wrong" page.
If you want details on the error, use Windows' events viewer or ELMAH or employ some logging mechanism.