asp.net + exceptions and redirecting - asp.net

My intention is to log an error(I am using Log4Net) when an exception is caught and redirect to a pretty looking page with some error message. I have a class that returns a Type T object , mostly a DataSet.
In my Catch statement I wrote this, it works but I am not sure if there's a more appropriate way of handling, can someone please advice. Thanks. Note that the throw cannot be omitted because the class has a return type.:
catch (Exception ex)
{
log.Error(ex);
HttpContext.Current.Response.Redirect("~/errorPage.aspx");
throw ex;
}

It depends upon how you want to handle error on the page, In general , unhandled exception should be bubbled up to application_error in gloabl.asax file to it generic.Here is one simple way to handle this error.
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();
}

Related

Using ELMAH and Application_Error at the same time

We have an ASP.NET MVC 3 application that is configured to use ELMAH. We also have code in our Application_Error method like this. Both ELMAH and our custom code log to a database.
protected void Application_Error(object sender, EventArgs e)
{
MvcApplication app = (MvcApplication)sender;
HttpContext httpContext = app.Context;
Exception ex = app.Server.GetLastError();
HttpException httpException = ex as HttpException;
//log the error with our custom logging
Server.ClearError();
if (httpContext.IsCustomErrorEnabled) //only show custom error if enabled in config
{
httpContext.Response.Clear();
httpContext.ClearError();
//show our own custom error page here
}
}
The problem (not really a problem, but whatever) we see is that both ELMAH and our custom code log the exception to the DB. I would expect calls to Server.ClearError() and httpContext.ClearError would handle the error and it would never get to ELMAH. But, does the fact that the error is being logged twice imply that ELMAH and application_error are running basically in parallel and they both receive the unhandled exception at the same time? If so is there anyway to tell ELMAH to ignore the error?
Our intent is to only have ELMAH handle an error if something goes REALLY wrong, like in the ASP.NET pipeline after elmah is registered, but before the MVC application would be running.
The issue is that it is logging to ELMAH first. So yes you can tell it not to log to ELMAH using e.Dismiss(): The ErrorLog_Filtering function below is hit before Application_Error. So add this function and any needed logic you need to determine if you want it in ELMAH or not.
void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e)
{
//get the exceptions like:
Exception m = e.Exception;
Exception ex = e.Exception.GetBaseException();
//tell it not to log the error in ELMAH like (based on whatever criteria you have):
e.Dismiss();
//Application_Error will be hit next
}
protected void Application_Error(object sender, EventArgs e)
{
//your logic
}

Display exception message using JavaScript in Base Page's OnError event

I want to display all unhandled excpetions in the appplication using Javascript. For this I have defined onError event inside my custom base class of my pages. Here is the code for my Base Page:
namespace Loan
{
public class BasePage : System.Web.UI.Page
{
public BasePage()
{
}
protected override void OnError(EventArgs e)
{
//Report Error
Exception ex = Server.GetLastError();
if (ex is HttpUnhandledException && ex.InnerException != null)
{
ex = ex.InnerException;
}
var _message = "Error : "+ ex.Message.ToString();
DisplayAlert(_message);
Server.ClearError();
return;
}
protected virtual void DisplayAlert(string message)
{
ClientScript.RegisterStartupScript(
this.GetType(),
Guid.NewGuid().ToString(),
string.Format("alert('{0}');", message.Replace("'", #"\'")),
true
);
}
}
}
The alert is never displayed for an unhandled exception. However, if I call the DisplayAlert from any Page
base.DisplayAlert(ex.Message);
the javascript alert is displayed. How can I get the javascript alert to be displayed for the unhandled exceptions from the base page.Or is there any other way to display these exception messages to the user. I don't want to redirect them to a generic error page as it sends them back and forth.
This is expected. If the exception is unhandled, the OnError event on BasePage will execute and your child page won't continue to execute, there's nothing to render as the BasePage is pure code. If you want to spit out the alert you'd need to write directly to the Response but you should still see a blank page after an unhandled exception occurs.
protected virtual void DisplayAlert(string message)
{
Response.Write(string.Format("<script>alert('{0}');</script>", message.Replace("'", #"\'")));
}
Of course, when you call DisplayAlert directly, it works because you are just calling a method, the Page execution continues normally.
I frankly dislike your approach. You should log the exception and redirect to another page, the typical Oooooooooopsss, me screwed up kind of thing.

NHibernate throws "Invalid operation. The connection was closed." exception

I have a code piece to record user data in Session_End event of Global.asax. It is working but sometimes it throws "Invalid operation. The connection was closed" exception. I have failed to replicate this situation on development server. It only occurs on application server. What is wrong? Thanks.
protected void Session_End(object sender, EventArgs e)
{
try
{
userlog = UserLog.LoadBySessionAndLogoutTime(NHibernateHTTPModule.CurrentSession, Session.SessionID, null);
userlog.LogoutTime = DateTime.Now;
UserLog.Update(NHibernateHTTPModule.CurrentSession, userlog);
}
catch (Exception exception)
{
Mail.SendMail("Error", error);
}
}
It would help if you explain where you open and close your nhibernate session. Unless you say the opposite I'll assume that you use "Open Session in View" pattern.
The user session ends outside of the scope of a request so if you open a nhibernate session on each request it won't be available when you try to log.
You should verify if you have an opened nhibernate session before logging. If none is active, you'll need to open a new one.
Chances are an Exception relating to an NHibernate operation was thrown somewhere in your code. Any NHibernate exception will invalidate the session.
So there is some condition on the application server that is different from your dev environment that contributes to the error. You could try logging it on the application server:
protected void Application_Error()
{
Exception myError = null;
if(HttpContext.Current.Server.GetLastError() != null)
{
// log error
myError = Server.GetLastError();
....
}
}
in global.asax will intercept all errors so you can log them.

ASP.NET ToolkitScriptManager AsyncPostBackError - throw exception from Content Page

Wonder if anyone can help. I'm trying to implement the ToolScriptManager OnAsyncPostBackError.
The ToolkitScriptManager is on the Masterpage and I've set the OnAsyncPostBackError property:
<ajax:ToolkitScriptManager ID="ToolkitScriptManager"
runat="server" EnablePartialRendering="true"
OnAsyncPostBackError="ScriptManager_AsyncPostBackError">
</ajax:ToolkitScriptManager>
On my content page I'm catching an exception and, logging it and then throwing it
private void LogError(Exception ex, bool full)
{
...
_presenter.LogError(this, error, ex);
throw new ApplicationException(
"Error Occured",
ex
);
}
where it then gets picked up by the handler on the Master Page
protected void ScriptManager_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
if (e.Exception.Data["GUID"] != null)
{
string _message =
(
e.Exception.InnerException != null
) ? e.Exception.InnerException.Message : e.Exception.Message;
ToolkitScriptManager.AsyncPostBackErrorMessage = _message +
" When reporting this error use the following ID: " +
e.Exception.Data["GUID"].ToString();
}
else
{
ToolkitScriptManager.AsyncPostBackErrorMessage =
"The server could not process the request.";
}
}
This all works as expected, I'm picking up the error via the PageRequestManager EndRequest and displaying on the page
The problem is that I'm getting an Application_Error in my Global.asax stating that an Exception of type 'System.Web.HttpUnhandledException' was thrown.
I kinda get it I think, cause I'm throwing the exception which is not caught by a catch I'm assuming?!
Any advice on what I'm missing, or where in fact I'm going wrong?
Thanks in advance!
Ian

Filtering signalled exceptions out of Elmah error mails

I've implemented a wrapper method around Elmah's Error Signaling, where a raised exception is only seen by Elmah for logging and mailing, but now I'd like to filter only these signalled exceptions out of the mailing, but still log them. How can I do this?
This is my simple wrapper:
public void LogException(Exception exception)
{
ErrorSignal.FromContext(HttpContext.Current).Raise(exception);
}
I've thought of wrapping the input exception in a custom SignalledException, and filtering those out of mailing, but then my logs get full of SignalledExceptions, and not the real exceptions.
Any other ideas please?
Elmah filtering works mainly on exception types. Programmatic filtering would allow me to examine information added to an exception, but I have yet to come across an Exception type with an ElmahFilteringData property, and I prefer not to 'invade' the exceptions I want logged. Here is how I accomplished only sending email notificatins for certain signalled exceptions:
First I have a special wrapper exception, purely for telling Elmah not to send an email notification for exceptions of this type:
public class ElmahEMailBlockWrapperException: Exception
{
public const string Explanation = "This is a wrapper exception that will be blocked by Elmah email filtering. The real exception is the InnerException";
public ElmahEMailBlockWrapperException(Exception wrappedException):base(Explanation, wrappedException) {}
}
Then, when I raise an exception I normally only want logged and not emailed, but maybe sometimes emailed, I use this code in my exception logging service:
public void LogException(Exception exception, bool includeEmail)
{
if (includeEmail)
{
ErrorSignal.FromContext(HttpContext.Current).Raise(exception);
}
else
{
// Wrap the input exception in a special exception type that the Elmah email filter can block.
var wrappedException = new ElmahEMailBlockWrapperException(exception);
ErrorSignal.FromContext(HttpContext.Current).Raise(wrappedException);
}
}
Now, in the Elmah filter events in Global.asax, I unwrap the exception to log it, and if it is wrapped, dismiss it from the email notification pipeline:
public void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e)
{
// If the exception was wrapped in a ElmahEMailBlockWrapperException exception to be blocked by the ErrorMail filter, the InnerException
// of the the ElmahEMailBlockWrapperException is the real exception to be logged, so we extract it, log it, and dismiss the wrapper.
var ebw = e.Exception.GetBaseException() as ElmahEMailBlockWrapperException;
if (ebw != null)
{
ErrorLog.GetDefault(HttpContext.Current).Log(new Error(ebw.InnerException));
e.Dismiss();
}
}
public void ErrorMail_Filtering(object sender, ExceptionFilterEventArgs e)
{
// If the exception was wrapped, i.e. raised only to be logged by Elmah and not emailed, dismiss it.
if (e.Exception.GetBaseException() is ElmahEMailBlockWrapperException)
{
e.Dismiss();
}
}

Resources