Using ELMAH and Application_Error at the same time - asp.net

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
}

Related

Google Recaptcha Validation ASP.NET

protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
Recaptcha.RecaptchaControl mycaptcha = (Recaptcha.RecaptchaControl)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("RecaptchaControl1");
mycaptcha.Validate();
Boolean answer = mycaptcha.IsValid;
if (answer == false)
{
((CancelEventArgs)e).Cancel = true;
}
}
Hi above is my code for Validating Google Recapture, I am using a CreateUserWizard form on Visual Studio.
The code is fine until I run it and an error appears stating
An exception of type 'System.NullReferenceException' occurred in App_Web_whsxk5eb.dll but was not handled in user code
Additional information: Object reference not set to an instance of an object.
for the line mycaptcha.Validate();
I'm not sure how to fix it.

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.

Which ASP.NET life cycle events fire after HttpApplication.Error?

I want to know which parts of the ASP.NET request life cycle happen after an error is handled via the HttpApplication.Error event. Specifically, which of the events listed at http://msdn.microsoft.com/en-us/library/bb470252.aspx#Stages fire after an error? I know that EndRequest still fires, and I suspect that PreSendRequestHeaders and PreSendRequestContent fire as well, but aside from these I have no idea.
Does it depend on when in the life cycle the error occurs? Does it depend on whether I call Server.ClearError() in the error handler?
I'm asking this question because I don't know if I should be calling HttpApplication.CompleteRequest() from my error handler.
The best way is to catch server last error and appdomain exceptions.
All of them can be done in Global.asax.cs file.
Check the following steps:
1- In Global.asax.cs, catch the last error and log it.
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Server.ClearError();
log.Error("Application Error caught in Global ", exception);
}
2- Add an event handler for UnhandledException event on AppDomain, this should be added to the Application_Start :
protected void Application_Start(object sender, EventArgs e)
{
//....
AppDomain.CurrentDomain.UnhandledException
+= new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
3- And here is the implementation of CurrentDomain_UnhandledException:
void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
if (e != null)
log.Error("Domain Unhandled Exception: ", e.ExceptionObject as Exception);
}
Happy coding :)
The LogRequest event is raised even if an error occurs. You can provide an event handler for the LogRequest event to provide custom logging for the request.
for further details on http://msdn.microsoft.com/en-us/library/system.web.httpapplication.logrequest.aspx
If your application generates custom error output, suppress the default error message that is generated by ASP.NET by a call to the ClearError method in the HttpApplication.Error Event.
I didn't check, but I think it depends.
An error can be raised in any page event (Init/Load/PreRender).
After the error is raised, if you clear the error, the page lifecycle is continued from where it was.
The exception that raises the Error event can be accessed by a call to GetLastError method. If your application generates custom error output, suppress the default error message generated by ASP.NET by a call to the ClearError method.
void Application_Error(Object sender, EventArgs e)
in global.asax
http://msdn.microsoft.com/en-us/library/24395wz3%28v=vs.100%29.aspx
http://msdn.microsoft.com/en-us/library/fwzzh56s%28v=vs.100%29.aspx

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();
}
}

Why can't my host (softsyshosting.com) support BeginRequest and EndRequest event handlers?

I heard good things about Softsys Hosting and so I decided to move my ASP.NET MVC solution over to them. But it would not run on them. I was able to pinpoint the problem to my BeginRequest event handlers. If I had them I'd get an error. Here is my code.
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
void MvcApplication_EndRequest(object sender, EventArgs e)
{
}
void MvcApplication_BeginRequest(object sender, EventArgs e)
{
}
I could reproduce the problem by just creating the default ASP.NET MVC application and adding the above code. The strange thing is this code worked fine on my old host and it only crashes on my new (shared) host. If I have these event handlers in my code I get this error:
Server Error in '/' Application.  
Object reference not set to an
instance of an object. 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.NullReferenceException: Object
reference not set to an instance of an
object.
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.
Stack Trace:
[NullReferenceException: Object
reference not set to an instance of an
object.]
System.Web.PipelineModuleStepContainer.GetStepArray(RequestNotification
notification, Boolean isPostEvent) +27
System.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification
notification, Boolean isPostEvent) +11
System.Web.PipelineStepManager.ResumeSteps(Exception
error) +205
System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext
context, AsyncCallback cb) +91
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest
wr, HttpContext context) +514
I tried troubleshooting this with Softsys, but they were not very helpful, basically they just confirmed that I had turned on the "ASP.NET Pipeline (MVC)" functionality within my admin control panel.
Can someone:
Tell me if I've coded something wrong
Show me a work-around
Explain to me why this error is occuring on one host and not the other.
You need register your handlers in each HttpApplication instance. There may be several pooled instances of HttpApplication. Application_Start is called only once (for IIS 6 and IIS 7 in classic mode - on the first request, for IIS 7 integrated mode - on web app start, just before any request). So to get all working you need to add events handlers in overrided Init method of HttpApplication or in constructor of it. If you add them in constructor - these handlers will be invoked first, even before the handlers of registered modules.
So your code should look like this:
public class MySmartApp: HttpApplication{
public override void Init(){
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
protected void Application_Start(){
RegisterRoutes(RouteTable.Routes);
}
}
or like this:
public class MySmartApp: HttpApplication{
public MySmartApp(){
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
protected void Application_Start(){
RegisterRoutes(RouteTable.Routes);
}
}
Looks to me like you went from IIS 6 or IIS 7 Classic mode to IIS 7 Integrated mode. In IIS 7 integrated mode, the Request processing was decoupled from application start. This article explains the why's and wherefores.
To fix it, you'll need to move your code to Application_BeginRequest instead.

Resources