I recently discovered that the IIS worker process in production was crashing 2-3 times per week. I noticed in the exception logs that the its because of an UnhandledException. I investigated and found that the Global.asax had no Server.Transfer call.
I then did some googling and it appears that it's better to use Response.Redirect. Is this true, I keep on getting mixed comments on this...
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
if (null != Context && null != Context.AllErrors)
System.Diagnostics.Debug.WriteLine(Context.AllErrors.Length);
//bool isUnexpectedException = true;
HttpContext context = ((HttpApplication)sender).Context;
Exception ex = context.Server.GetLastError();
if (ex.InnerException != null)
ex = ex.InnerException;
LogManager.ExceptionHandler(ex);
Server.Transfer("GeneralError.aspx");
}
It depends on if you would want your user to see the "redirection". Personally I would use Response.Redirect for this case.
Check out this answer on the difference between the two:
https://stackoverflow.com/a/224577/1260077
Related
I am using Application_Error method to handle and log exceptions. I need to pass Exception from Global.asax to Error controller
I tried
this.Session["w"] = (Exception)exception;
but that's not working.
My code looks like this:
protected void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
if (exception != null)
{
this.Session["w"] = (Exception)exception;
Server.ClearError();
ExceptionManager.LogExceptionToTextFile(exception);
ExceptionManager.LogExceptionToEmail(exception);
if (!Response.IsRequestBeingRedirected)
Response.Redirect("~/Error/Index");
}
}
You can try something like this
Exception exception = Server.GetLastError();
string errorId = Guid.NewGuid().ToString();
if (exception != null)
{
this.Application.Lock();
this.Application[errorId] = exception;
this.Application.Unlock();
Server.ClearError();
ExceptionManager.LogExceptionToTextFile(exception);
ExceptionManager.LogExceptionToEmail(exception);
if (!Response.IsRequestBeingRedirected)
Response.Redirect("~/Error/Index?errorId="+errorId);
}
and in the error controller
var Exception = (Exception)Application[Request["errorId"]]
EDIT:
If you want to use sessions, You might also want to replace
Response.Redirect("~/Error/Index");
With
Response.Redirect("~/Error/Index", false);
Reason you loose your session, is due to thread cancellation.
You can read more about it at When Should I Use Response.Redirect(url, true)?:
I made an error; the page directs users in case of error in any applications within the website. I made Global.asax rather than using Webconfig. My question is : Is it possible to redirect user from Global.asax for those statusCodes "401", "404" and "500" in case of error rather than using Webconfig ?
In other words, using Global.aspx rather than Webconfig !? I am just curious to know.
Thank you
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = this.Server.GetLastError();
if(ex is HttpException)
{
HttpException httpEx = (HttpException)ex;
if(httpEx.GetHttpCode() == 401)
{
Response.Redirect("YourPage.aspx");
}
}
}
Yes it is possible. Here is little code example. This should be added in Global.asax.cs.
Never set customErrors to Off in your Web.config file if you do not have an Application_Error handler in your Global.asax file. Potentially compromising information about your Web site can be exposed to anyone who can cause an error to occur on your site.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
// Get the exception object.
Exception exc = Server.GetLastError();
// Handle HTTP errors
if (exc.GetType() == typeof(HttpException))
{
// The Complete Error Handling Example generates
// some errors using URLs with "NoCatch" in them;
// ignore these here to simulate what would happen
// if a global.asax handler were not implemented.
if (exc.Message.Contains("NoCatch") || exc.Message.Contains("maxUrlLength"))
return;
//Redirect HTTP errors to HttpError page
Server.Transfer("HttpErrorPage.aspx");
}
// For other kinds of errors give the user some information
// but stay on the default page
Response.Write("<h2>Global Page Error</h2>\n");
Response.Write(
"<p>" + exc.Message + "</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");
// Log the exception and notify system operators
ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);
// Clear the error from the server
Server.ClearError();
}
Also once can get error code like
exc.GetHttpCode() == 403 so that
if (exc!= null && httpEx.GetHttpCode() == 403)
{
Response.Redirect("/youraccount/error/forbidden", true);
}
else if (exc!= null && httpEx.GetHttpCode() == 404)
{
Response.Redirect("/youraccount/error/notfound", true);
}
else
{
Response.Redirect("/youraccount/error/application", true);
}
Also see Custom error in global.asax
I'm new to ASP.NET and I have a very basic site that I just want to grab all Application Errors and email them to me, while giving the user a error page. I read a lot on the subject and seems to be a lot of information. Below is what I came up with but I'm having problems keeping the Exception in session so I can email it to me.
I keep getting a NullReferenceException was unhandled by user code on the ex.Message from the Error.aspx.cs file.
Any thoughts?
Global.asax.cs-
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
HttpContext.Current.Response.Redirect("~/Error.aspx");
}
Error.aspx.cs-
public partial class Error : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Exception ex = (Exception)Session["Exception"];
this.SendEmail(ex);
Session.Remove("Exception");
}
}
private void SendEmail(Exception ex)
{
string body = "An exception occured at "
+ DateTime.Now.ToLongTimeString()
+ " on " + DateTime.Now.ToLongDateString()
+ "<br />" + ex.Message; //ERROR HERE
MailMessage msg = new MailMessage("from#email.com", "to#email.com");
msg.Subject = "Exception in Portal Website";
msg.Body = body;
msg.IsBodyHtml = true;
SmtpClient client = new SmtpClient("localhost");
client.Send(msg);
}
}
Your problem is that you are never setting Session["Exception"], so on your Error.aspx, Exception ex is always going to be null... and then doing ex.Message will throw the NullReferenceException. Even if you fix that and appropriately set Session["Exception"], what you are doing isn't ideal.
You could just send the email from the Application_Error function.
Your Response.Redirect (MSDN Entry) is going to cause ANOTHER exception (ThreadAbortException)
You should look at implementing ELMAH. It is easy to implement and does everything you want to do.
But if all you want to do is fix your code, just move the send email logic to Application_Error and then you don't have to worry about Session.
What I did in a similar instance is to throw all exceptions and then in your global.asax uses the Application_Error method to perform any work you need to with the error message.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
string exception;
Exception ex = Server.GetLastError();
if (ex.InnerException != null)
{
Exception innerException = ex.InnerException;
exception = ex.InnerException.Message;
}
else
{
exception = ex.Message;
}
//Send email here
//redirect to error page
}
I don't see you pushing the exception object to session, why not move the SendEmail method to global.ascx and SendEmail then redirect user to Error page. There are third party plugins like ELMAH that can do all this easily for you with simple configurations.
I'm in a similar bind. I'm going to check out ELMAH, but my project has a huge restriction on Open Source Projects, yours may to. Sucks to be me!
In which case I'd suggest creating a logging function for the message that you can call directly from the Global.asax. Something like:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
LogException(ex);
HttpContext.Current.Response.Redirect("~/Error.aspx");
}
//Somewhere Else
void LogException(Exception ex)
{
WriteExceptionToEndOfTextFile(ex);
SendEmail();
}
This way if someone decides they want to suppress our exceptions, they can still properly handle the exception.
I have a website on appharbor.
I know there is logentries for logs on demand.
But, how can I see all unhandled server-side exceptions?
I have found this snippet (to put int Global.ascx), but couldn't find what are all the required dlls to reference.
protected void Application_Error(object sender, EventArgs e)
{
try
{
var exception = Server.GetLastError();
var logEntry = new LogEntry
{
Date = DateTime.Now,
Message = exception.Message,
StackTrace = exception.StackTrace,
};
var datacontext = new LogDBDataContext();
datacontext.LogEntries.InsertOnSubmit(logEntry);
datacontext.SubmitChanges();
}
catch (Exception)
{
// failed to record exception
}
}
AppHarbor already logs application errors, you can inspect them by clicking "Errors" in the menu to the left of the application dashboard.
Another great option is to add Elmah to your AppHarbor application, but remember to lock down Elmah view.
Should you still want to use the snippet above, then take a look at the full sample to see what other dependencies are required.
So in the Global.asax is this:
protected void Application_Error(object sender, System.EventArgs
{
Session["CustomError"] = Server.GetLastError();
Server.ClearError();
Response.Redirect("~/ErrorPage.aspx");
}
And in ErrorPage.aspx is this:
private void Page_Load(object sender, System.EventArgs e)
{
Exception currentException = ((Exception)Session["CustomError"]).InnerException;
// Writes the error message
if (currentException != null)
txtErrorMessage.Text = currentException.Message;
// Loops through the inner exceptions.
currentException = (Exception)Session["CustomError"];
while (currentException != null)
{
message.Append(currentException.Message).Append("\r\n").Append(currentException.StackTrace);
message.Append("\n==============================================\n");
currentException = currentException.InnerException;
}
As this is old 1.0 code it barfs when converted to a 3.5 Global.asax file. It tells me that "Session" is not available and also that I can't redirect?? I think one of the issues may be that there is also an error being thrown from Application_Start. But if I comment out all the application start code I still get errors but they never get redirected to the error page.
This link might help: Exceptional Gotchas!.
In addition, use the web.config file to define your default redirect page for errors.