I have an asp.net application and I am trying to handle custom exception using Application_Error. It works nicely but I have new requirement to set the error data in Session object(or any object that can maintain state) and redirect to Error.aspx page. THere I am just removing the error messages after reading them.
So, Whatever I add to session object(or if I change a previously existing value) in Application_error and when I call Redirect. In the error.aspx I don't see any of the value as if Session was in readonly mode in Application_error.
I tried by calling
session.IsReadOnly
to see if its read only. But it returns false!!
I've just come across this problem myself and, after a couple of hours of messing around, managed to solve it. The issue is that Application_Error() clears the session after executing as part of some sort of "cleanup" routine which you need to stop.
The solution I found is as follows:
Call Server.ClearError(); - this clears the last error from the application and stops the "cleanup" taking place, thus preserving session.
The (unwanted imho) side-effect of this is that it no longer performs the automatic redirect to the error page, so you need to explicitly call Response.Redirect("~/error.aspx");
So, something like this:
protected void Application_Error(object sender, EventArgs e)
{
// Grab the last exception
Exception ex = Server.GetLastError();
// put it in session
Session["Last_Exception"] = ex;
// clear the last error to stop .net clearing session
Server.ClearError();
// The above stops the auto-redirect - so do a redirect!
Response.Redirect("~/error.aspx");
}
If you don't want to hard-code the URL, you could grab the defaultRedirect URL directly from the customerrors section in the web.config, which would give you something like this:
protected void Application_Error(object sender, EventArgs e)
{
// Grab the last exception
Exception ex = Server.GetLastError();
// put it in session
Session["Last_Exception"] = ex;
// clear the last error to stop .net clearing session
Server.ClearError();
// The above stops the auto-redirect - so do a redirect using the default redirect from the customErrors section of the web.config!
var customerrors = (CustomErrorsSection)WebConfigurationManager.OpenWebConfiguration("/").GetSection("system.web/customErrors");
Response.Redirect(customerrors.DefaultRedirect);
}
You could use the Cache and an appropriate naming strategy for your key, like this:
protected void Application_Error(object sender, EventArgs e)
{
HttpContext.Current.Cache["error:" + Session.SessionID] = Server.GetLastError();
Response.Redirect("Error.aspx");
}
in the Error.aspx page you ca read it like this:
var error = Cache["error:" + Session.SessionID];
Check this, the problem is with the redirect call.
Don't redirect after setting a Session variable (or do it right)
Add a directive to the Global.asax file, Imports the System.Web Namespace
<%# Import Namespace="System.Web" %>
void Application_Error(object sender, EventArgs e) {
string message = Server.GetLastError().Message;
Session["error"] = message;
Server.Transfer("Error.aspx");
}
Write the error message added in the sesion object in the Error.aspx page
protected void Page_Load(object sender, EventArgs e){
if (!this.IsPostBack)
Response.Write(Session["error"].ToString());
}
The problem might that the AcquireRequestState event might not have fired when the exception was raised in your application, you will be able to set a session value only after this particular event is fired as this is the stage where the application state is set
Related
I've managed to hook up SharpRaven to log and capture errors successfully from both MVC and Web API controllers, but have been unable to log and capture 404 errors.
I'm attempting to do this through Application_Error like so:
public class MvcApplication : System.Web.HttpApplication
{
RavenClient _RavenClient;
protected void Application_Start()
{
_RavenClient = new RavenClient(ConfigurationManager.AppSettings["RavenClient:DNS"]);
...
}
protected void Application_Error(object sender, EventArgs e)
{
_RavenClient.Capture(new SentryEvent(Server.GetLastError()));
}
}
If I set a break point on the _RavenClient.Capture(...) I can see the error getting captured, but the 404 errors captured here never turn up in https://sentry.io/
This is also true for non-404 exceptions that hit this line of code, if I disable the other controller integrations.
Any ideas why this isn't working fully? Is there a better way I could be doing this that might have a better chance at working?
Everything works as desired if I create the RavenClient when I need it within the Application_Error method itself. Seems there must be a problem with creating the client in Application_Start and then using it later.
This is my modified working code:
protected void Application_Error(object sender, EventArgs e)
{
new RavenClient(ConfigurationManager.AppSettings["RavenClient:DNS"])
.Capture(new SentryEvent(Server.GetLastError()));
}
I have an asp.net application and I am trying to handle custom exception using Application_Error. It works nicely but I have new requirement to set the error data in Session object(or any object that can maintain state) and redirect to Error.aspx page. THere I am just removing the error messages after reading them.
So, Whatever I add to session object(or if I change a previously existing value) in Application_error and when I call Redirect. In the error.aspx I don't see any of the value as if Session was in readonly mode in Application_error.
I tried by calling
session.IsReadOnly
to see if its read only. But it returns false!!
I've just come across this problem myself and, after a couple of hours of messing around, managed to solve it. The issue is that Application_Error() clears the session after executing as part of some sort of "cleanup" routine which you need to stop.
The solution I found is as follows:
Call Server.ClearError(); - this clears the last error from the application and stops the "cleanup" taking place, thus preserving session.
The (unwanted imho) side-effect of this is that it no longer performs the automatic redirect to the error page, so you need to explicitly call Response.Redirect("~/error.aspx");
So, something like this:
protected void Application_Error(object sender, EventArgs e)
{
// Grab the last exception
Exception ex = Server.GetLastError();
// put it in session
Session["Last_Exception"] = ex;
// clear the last error to stop .net clearing session
Server.ClearError();
// The above stops the auto-redirect - so do a redirect!
Response.Redirect("~/error.aspx");
}
If you don't want to hard-code the URL, you could grab the defaultRedirect URL directly from the customerrors section in the web.config, which would give you something like this:
protected void Application_Error(object sender, EventArgs e)
{
// Grab the last exception
Exception ex = Server.GetLastError();
// put it in session
Session["Last_Exception"] = ex;
// clear the last error to stop .net clearing session
Server.ClearError();
// The above stops the auto-redirect - so do a redirect using the default redirect from the customErrors section of the web.config!
var customerrors = (CustomErrorsSection)WebConfigurationManager.OpenWebConfiguration("/").GetSection("system.web/customErrors");
Response.Redirect(customerrors.DefaultRedirect);
}
You could use the Cache and an appropriate naming strategy for your key, like this:
protected void Application_Error(object sender, EventArgs e)
{
HttpContext.Current.Cache["error:" + Session.SessionID] = Server.GetLastError();
Response.Redirect("Error.aspx");
}
in the Error.aspx page you ca read it like this:
var error = Cache["error:" + Session.SessionID];
Check this, the problem is with the redirect call.
Don't redirect after setting a Session variable (or do it right)
Add a directive to the Global.asax file, Imports the System.Web Namespace
<%# Import Namespace="System.Web" %>
void Application_Error(object sender, EventArgs e) {
string message = Server.GetLastError().Message;
Session["error"] = message;
Server.Transfer("Error.aspx");
}
Write the error message added in the sesion object in the Error.aspx page
protected void Page_Load(object sender, EventArgs e){
if (!this.IsPostBack)
Response.Write(Session["error"].ToString());
}
The problem might that the AcquireRequestState event might not have fired when the exception was raised in your application, you will be able to set a session value only after this particular event is fired as this is the stage where the application state is set
I have an .aspx page with some synchronous code that's taking a very long time to execute and is triggering a request timeout. For example:
protected void Page_Load(object sender, EventArgs e)
{
var log = LogManager.GetLogger("test");
log.Debug("Before thread sleep...");
Thread.Sleep(99999999);
log.Debug("After thread sleep.");
}
In my Global.asax, I've added some error handling that will e-mail out any exceptions:
protected void Application_Error(Object sender, EventArgs e)
{
var exception = HttpContext.Current.Server.GetLastError();
SendExceptionEmail(exception);
}
Problem is, in Global.asax, I only have access to the request and response and the exception that occurred, but not the output from the logger. How do I get access to this in Global.asax? Without it, I can't tell what piece of code is hanging the application without digging through the log files, which is a major chore to filter.
The 'log' object is a static variable, and it is not correct to try to fetch it in Global.asax Application_Error(). Depending on the current thread in thread pool, you might get unpredictable values in it.
A more secure approach could be along with log.Debug() to insert some Debug data into HttpContext.Current.Items. Then you can access these items in Application_Error() method.
Context.Items are considered as thread-safe and are recommended for use in cases like this.
Another way to do it would be to have log4net send the email for you using an email appender. See this example: http://sradack.blogspot.co.uk/2007/09/have-log4net-send-email-when-error.html
When I want to redirect a user who has lost session state back to the StartPage I find Response.Redirect("~/StartPage.aspx") causes the error "Response Redirect Cannot Be Called In A Page Callback". Therefore in a Page.IsCallback situation I want to add javascript to do the redirect - this works - see code below.
protected void ForceBackToStartPage()
{
if (Page.IsCallback)
{
string fullLoginUrl = ConvertRelativeUrlToAbsoluteUrl( "~/StartPage.aspx" );
string script = string.Format("window.location.href = '{0}';", fullLoginUrl);
ClientScriptManager cm = Page.ClientScript;
cm.RegisterClientScriptBlock(GetType(), "redirect", script, true);
//Response.Flush();
//Response.End();
}
else
{
Response.Redirect("~/StartPage.aspx");
}
}
After I have added the javascript in this section the code continues to process normally leaving this function and going off to other processing sections of the webpage - probematic as the user has no session data. Ideally I'd want processing of this web page to finish - and for the page to return in a valid state so that the user gets redirected.
Is this possible?
I thought Response.Flush(); Response.End(); might do the trick - but the webpage sent back to the browser causes XML Parse errors.
Further info: I check for missing session data in a few places (depending on the webpage - this code is in lots of web pages) - for instance - PageLoad and from some submit button methods.
Before the new method I used this code e.g.:
protected void Page_Load(object sender, EventArgs e)
{
if ((string)Session["OK"] != "OK")
{
// the session has timed out - take them back to the start page
Response.Redirect("~/StartPage.aspx");
}
...rest of processing
Now it's invoked like this:
protected void Page_Load(object sender, EventArgs e)
{
if ((string)Session["OK"] != "OK")
{
// the session has timed out - take them back to the start page
ForceBackToStartPage();
}
...rest of processing
so I could obviously use
else
{
...rest of processing
}
but I was hoping not to have to do that as SVN Source Control takes that to mean I've re-written the whole 'rest of processing' section. This is problematic as when I merge from a branch into the trunk it does not check I am not overwriting mods because it assumes it's all new code coming in.
Response.Redirect issues a "302 Moved" command that cannot be served asynchronously. Given that you're just registering a script when IsCallback=true, could you not also do it when IsCallback= false? Register a script that hooks up an event to the loaded event of the window and redirect the page from script instead of from the server.
I was thinking about this again recently and realised the very obvious answer. Forget nicely structured code, as being part of an error trap this is a special case, and use a return; after the 'ForceBackToStartPage' method invocation:
protected void Page_Load(object sender, EventArgs e)
{
if ((string)Session["OK"] != "OK")
{
// the session has timed out - take them back to the start page
ForceBackToStartPage();
return;
}
...rest of processing
}
As stated in the title my web application builds successfully, although every time I run it in debug mode I get the following .Net error:
If I hit refresh then the application gets no more errors until I next start it up again, any ideas?
Here is my global.asax file:
<%# Application Language="C#" Inherits="MyCompany.Web.MyApp.Shell.CustomWebClientApplication" %>
<script runat="server">
void Session_End(Object Sender, EventArgs e)
{
FormsAuthentication.SignOut();
}
protected void Session_Start(Object sender, EventArgs e)
{
if (Session.IsNewSession)
{
Response.Redirect(System.Web.Configuration.WebConfigurationManager.AppSettings["HomePage"]);
}
}
protected void Application_Error(Object sender, EventArgs e)
{
System.Exception oops = Server.GetLastError();
//Injection attack error handling
if (oops.GetBaseException() is System.Web.HttpRequestValidationException)
{
Response.Redirect("ErrorPage.aspx");
}
}
</script>
You have something which is trying to access a variable which is set to null (or hasn't been initialized). Do you have anything in the Global.asax or anything that fires on the start of the application? Do you have any asynchronous operations that fire on the start of the application?
Check on your Home.aspx page to see what is happening there. It looks like your application redirects to that page, so I would guess that on either the init or page_load event there is something which is executing that it causing the problem.
System.Exception oops
I think that this is source of problems. When there is no object returned from
Server.GetLastError();
then you will get NullReferenceException on line
oops.GetBaseException()
It makes perfect sense. On first run, oops is null (because no error occured before), thus throwing NullReferenceException. On second page refresh, GetLastError() returns object reffering previous errror (NullReferenceException) and page is displayed. Always check objects for null before accessing them.
Anyway, you can always try catching all runtime exceptions (Debug->Exceptions->Common Language runtime) and see where a problem is.
Sounds like an initialization issue. You're probably trying to use a resource before it's initialized, but by the time you refresh it's had time to be initialized.