Search code examples
c#asp.netevent-handlinghttpmoduleelmah

How do I append the SQL ELMAH_Error.ErrorID to the ELMAH Error Email Subject?


I'm using ELMAH to log errors to a SQL database AND send an email. I'd like to append the ELMAH_Error.ErrorId to the subject of the ELMAH email.

I'm saving the ErrorId ELMAH provides in the ElmahLog_Logged event into a session variable as I discovered in this question. Atif Aziz himself commented on this blog post the following information regarding this:

If one does want a crack at the logged Error during mailing, one would have to pick it up in the ErrorLogModule.Logged event. This could be handy, for example, to push the Id of the logged error into the mail. To do that, you'd stash away the Id from the Logged event into the HttpContext and use it later in the Mailing event. For this to work, the modules would have be registered such that the Mailing event occurs after the Logged event.

I thought that since the httpModules are added with ErrorLog first and ErrorMail second, that this would achieve registering the Mailing event after the Logged event. I suppose that's talking about order of the events, not the order the Modules are applied in.

How do you register the event order of HttpModules?

I have tried the code below to no avail. The code below prevents the email from sending, but the error is still logged to the SQL table.

Web.Config:

<system.web>
    <httpModules>
        <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
        <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
        <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
    <httpHandlers>
        <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
</system.web>

... and ...

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
        <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
        <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
        <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <handlers>
        <add name="Elmah" path="elmah.axd" verb="POST,GET,HEAD" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
    </handlers>
</system.webServer>

And of course the and are properly configured (I installed via NuGet).

Global.asax.cs:

protected void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
{
    Session["ElmahId"] = args.Entry.Id;
}

protected void ErrorMail_Mailing(object sender, ErrorMailEventArgs e)
{
    var elmahErrorId = Session["ElmahId"].ToString();
    e.Mail.Subject = String.Format("{0}, see ELMAH_Error.ErrorID = {1}", e.Mail.Subject, elmahErrorId);            
}

If I change the ErrorMail_Mailing event code in global.asax.cs to the following code, I receive the Email with the subject specified in the ErrorMail_Mailing event code as I should. I've even tried to just put Session.SessionID in the subject and that kills the email functionality. This makes me think that the ErrorMail_Mailing event does not have Session access. Is this correct?

protected void ErrorMail_Mailing(object sender, ErrorMailEventArgs e)
{
    e.Mail.Subject = "I changed the subject in global.asax";
}

Solution

  • The answer was incredibly easy. The ErrorMailEventsArgs.Error object contains the session information at the time of exception. The ErrorMail_Mailing even does not have access to the session context. So, the solution is as simple as pulling your variable from the ErrorMailEventArgs.

    protected void ErrorMail_Mailing(object sender, ErrorMailEventArgs e)
    {
        var elmahErrorId = e.Error.SessionVariables["ElmahId"].ToString();
        if (!string.IsNullOrEmpty(elmahErrorId))
            e.Mail.Subject = String.Format("{0}, see ELMAH_Error.ErrorID = {1}", e.Mail.Subject, elmahErrorId);
    }
    

    Also, simply by putting the ElmahId in Session in the ErrorLog_Logged event, if your ErrorMail handler is registered after ErrorLog (done by adding ErrorLog in web.config first), that session variable will be in the Session Variables section the standard ELMAH error email.

    protected void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
    {
        Session["ElmahId"] = args.Entry.Id;
    }
    

    Update: Atif Aziz brought up that the Errors.SessionVariables is not in the original ELMAH source, but in a patch instead. Here is my packages.config:

    <packages>
        <package id="elmah.corelibrary" version="1.2" />
        <package id="elmah" version="1.2.0.1" />
        <package id="elmah.sqlserver" version="1.2" />
    </packages>