Thomas Bandt

Über mich | Kontakt | Archiv

ELMAH mit ASP.NET MVC nutzen und Fehler loggen

ELMAH steht für Error Logging Modules and Handlers und ist kurz gesagt ein Plugin für ASP.NET-Anwendungen, mit dem Fehler, sprich Exceptions, geloggt werden können. Das Schöne daran ist, dass es sich ohne große Zeremonie installieren und sofort nutzen lässt, gleichzeitig aber auch konfigurier- und erweiterbar bleibt.

Die Features im Überblick:

Installation für ASP.NET MVC 3

Nachfolgend eine kurze Installationsanleitung, die im Prinzip aus Teilen besteht, die ich mir jetzt selbst zusammengesucht habe. Da ein elementarer und immer wieder verlinkter Blogpost inzwischen offline ist, nehme ich das hier vor allem mal als Dokumentation für mich selbst her ...

1. Download der Binaries

Die Dateien finden sich auf der Projektwebsite. Einfach runterladen und entpacken und die Elmah.dll aus dem 3.5er-Build ins Projekt einbinden, üblicherweise über einen /Shared-Ordner o.ä.

2. Datenbank konfigurieren

Im Ordner /db des Zips findet sich ein Script namens SQLServer.sql. Das einfach gegen eine beliebige Datenbank, in der die Fehler gespeichert werden sollen, ausführen. Die Fehlermeldung, die kommt, wenn man einen SQL Server älter als 2000 ;-) verwendet, kann man getrost ignorieren.

3. Referenz hinzufügen

Es wird lediglich eine Referenz auf die Elmah.dll benötigt - ein Fakt, der das Ganze für mich überhaupt so attraktiv macht.

4. Web.config konfigurieren

Die Konfiguration für den IIS7 bzw. MVC 3 weicht von der im mitgelieferten Sample-Web ab, daher hier komplett:

   1:  <?xml version="1.0" encoding="UTF-8"?>
   2:  <configuration>
   3:    <configSections>
   4:      <sectionGroup name="elmah">
   5:        <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
   6:        <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
   7:        <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
   8:        <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
   9:      </sectionGroup>
  10:    </configSections>
  11:    <connectionStrings>
  12:      <add name="elmah" connectionString="server=2008; database=Datenbankname; User ID=sa; password=Password"/>    
  13:    </connectionStrings>
  14:      <system.webServer>
  15:      <handlers>
  16:        <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" preCondition="integratedMode" type="Elmah.ErrorLogPageFactory, Elmah"/>
  17:      </handlers>
  18:      <modules runAllManagedModulesForAllRequests="true">
  19:        <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
  20:        <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
  21:        <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
  22:      </modules>
  23:      </system.webServer>
  24:    <elmah>
  25:      <security allowRemoteAccess="0" />
  26:      <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah" />
  27:    </elmah>
  28:  </configuration>

5. HandleError ...

Da MVC eine eigene Fehlerbehandlung mitbringt und diese die Exceptions auch als erledigt markiert, muss ein eigener Filter her, der ELMAH integriert. Warum und wieso ist in diesem Post beschrieben.

   1:  public class HandleErrorWithElmahAttribute : HandleErrorAttribute
   2:  {
   3:   
   4:      public override void OnException(ExceptionContext context)
   5:      {
   6:   
   7:          base.OnException(context);
   8:   
   9:          var e = context.Exception;
  10:          if (!context.ExceptionHandled   // if unhandled, will be logged anyhow
  11:              || RaiseErrorSignal(e)      // prefer signaling, if possible
  12:              || IsFiltered(context))     // filtered?
  13:              return;
  14:   
  15:          LogException(e);
  16:   
  17:      }
  18:   
  19:      private static bool RaiseErrorSignal(Exception e)
  20:      {
  21:          var context = HttpContext.Current;
  22:          if (context == null)
  23:              return false;
  24:          var signal = ErrorSignal.FromContext(context);
  25:          if (signal == null)
  26:              return false;
  27:          signal.Raise(e, context);
  28:          return true;
  29:      }
  30:   
  31:      private static bool IsFiltered(ExceptionContext context)
  32:      {
  33:              
  34:          var config = context.HttpContext.GetSection("elmah/errorFilter")as ErrorFilterConfiguration;
  35:          if (config == null)
  36:              return false;
  37:   
  38:          var testContext = new ErrorFilterModule.AssertionHelperContext(context.Exception, HttpContext.Current);
  39:          return config.Assertion.Test(testContext);
  40:   
  41:      }
  42:   
  43:      private static void LogException(Exception e)
  44:      {
  45:          var context = HttpContext.Current;
  46:          ErrorLog.GetDefault(context).Log(new Error(e, context));
  47:      }
  48:   
  49:  }

Damit das Logging greift, muss der Filter natürlich auch angewendet werden. Idealerweise in einem Basiscontroller, von dem alle anderen Controller dann ableiten, damit man die Deklaration nicht mehrfach durchführen muss.

   1:  [HandleErrorWithElmah]
   2:  public class BaseController : Controller
   3:  {
   4:     ...
   5:  }

Fertig

Das war's schon. Ab sofort werden alle Fehler in der Datenbank geloggt und können über /elmah.axd abgerufen werden, wahlweise über das Web-Interface oder als RSS-Feed, oder, oder, oder ... Happy logging.



« Zurück  |  Weiter »