ASP.NET Providers del 1 – Grundläggande Health Monitoring

Alla som skriver sidor i ASP.NET har någon gång fått fram "Yellow Screen Of Death", med ett felmeddelande som säger vad som har gått fel på sidan. Det finns många metoder för att säkra upp fel, det kan gå ut på att man kollar om värdet är giltigt, om en variabel är null osv, men det är i stort sett omöjligt att gardera sig mot alla fel som kan uppstå.

Ponera att databasservern helt plötsligt går ner, att nätverkssladden glappar eller att man helt enkelt har glömt att göra en koll någonstans i koden? Det här är exempel på sådant som inte är lätt att skydda sig mot, vilket leder till att det antagligen skickas en exception någonstans i koden.

I ASP.NET 2.0 så introducerades ett par olika providers, där - vad jag har sett - membership provider är den mest förekommande och används av väldigt många. En provider som däremot inte används alltför ofta, och som faktiskt inte många känner till är Health Monitoring. Ofta så brukar felmeddelanden helt enkelt fångas upp med try..catch, och sedan antingen ignoreras eller loggas med en egen loggningsmotor. Detta är faktiskt inte nödvändigt.

Med health monitoring så kan man lagra alla fel som uppstår (samt lagra egna undantag som kan visa om t.ex. en inloggning på sidan har fallerat eller liknande) och sedan hämta dem på olika sätt.

Om man inte anger något i web.config alternativt machine.config så lagras faktiskt alla exceptions automatiskt i Event Viewer. När man skapar membership-tabellerna för Membership Provider så kan man faktiskt samtidigt med samma verktyg (aspnet_regsql) skapa upp en tabell och en lagrad procedur som kan användas för loggning.

Jag kommer att till en början visa hur vi skapar upp en sida som genom att klicka på en knapp kastar ett felmeddelande, och sedan visa hur det lagras i Event Viewer, samt hur vi kan konfigurera SQL Server för att vi istället skall kunna lagra felen där, vilket gör att vi direkt på sidan kan lista alla felmeddelanden. Detta kan vara ett bra sätt för administratörer att enkelt se vad som händer på sidan, då det inte alltid är så att användarna kan eller vill meddela vad som har hänt på sidan. Vi kan inte spåra allt som har hänt (dvs vad användaren har gjort i detalj), men däremot kan vi få information om vilken användare som har fått vilket felmeddelande vid en aktuell tidpunkt.

Just den här artikeln kommer att innehålla de grundläggande bitarna, och i en följande artikel kommer jag även att ta upp hur vi kan skapa en egen provider där vi lagrar informationen så som vi själva vill lagra den (i en egenskapad provider kan man välja att spara i vilket format man vill, maila, skicka ett SMS eller vad man nu önskar).

Det första vi behöver göra är att skapa upp en enkel ASP.NET-sida med en knapp som kastar ett undantag.

HTML

   1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HealthMonitoring._Default" %>
   2:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   3:  <html xmlns="http://www.w3.org/1999/xhtml">
   4:  <head runat="server">
   5:      <title>Demo - Health Monitoring</title>
   6:  </head>
   7:  <body>
   8:      <form id="form1" runat="server">
   9:          <h1>Demo Health Monitoring</h1>
  10:          <asp:Button ID="btnError" runat="server" onclick="btnError_Click" 
  11:   
  12:  Text="Error!" />
  13:      </form>
  14:  </body>
  15:  </html>

Code behind:

   1:  using System;
   2:   
   3:  namespace HealthMonitoring
   4:  {
   5:      public partial class _Default : System.Web.UI.Page
   6:      {
   7:          protected void btnError_Click(object sender, EventArgs e)
   8:          {
   9:              throw new Exception("Kastar en exception!");
  10:          }
  11:      }
  12:  }

Det som visas när vi klickar på knappen är:

1

Det som sker här är att användaren vid klick på knappen får upp ett undantag på grund av att något har gått fel. Som administratör vill vi sedan få tag i den här informationen - även om användaren själv inte har meddelat att felet uppstod. Genom att på servern (i det här fallet lokalt på datorn, annars servern på webbhotellet om vi har möjlighet att gå in där via remote desktop eller liknande) kika i Event Viewer så kan vi få upp information om när detta uppstod, och vem som surfade in på sidan (förutsatt att besökaren är autentiserad) samt få information om vad som hände. Vi kan alltså få tag samma information som visades.

Som standard är det just Event Viewer som används för att lagra undantag, och det här gäller som standard i ASP.NET 2.0 och senare.

När vi kikar i Event Viewer så får vi upp detta meddelande:

2

Vi har även möjlighet att lagra felmeddelanden med ett visst intervall och skippa allt med t.ex. 30 sekunders mellanrum vilket kan vara bra för icke kritiska fel då vi riskerar att få en överfull Event Viewer annars, vi kan lagra undan alla felmeddelanden i minnet och sedan skicka in dem till datakällan (för tillfället Event Viewer) med ett visst mellanrum eller när ett visst antal fel finns i minnet, eller helt enkelt bara välja att lagra undan felmeddelanden med en viss felkod.

Alla dessa inställningar kan vi ställa in i web.config.

För att i web.config ändra inställningar för Health Monitoring så finns det under <system.web> ett element som heter <healthMonitoring>. Där har vi i sin tur fem olika element med inställningar:

  • eventMappings
    • name - Namn på mappningen.
    • type - Klass som används för mappningen.
    • startEventCode - Siffran för första felkoden som skall loggas.
  • endEventCode - Siffran för sista felkoden som skall loggas.
    • providername - Namn på provider.
    • type - Klass som ärver ProviderBase.
    • buffer - Avgör om buffern skall vara aktiverad, om true så måste bufferModes vara konfigurerad.
    • connectionStringName - Eventuell connectionstring från <connectionStrings> som visar var datan skall lagras.
    • maxEventDetailsLength - Maximal längd på text med information om eventet.
  • rules
    • name - Namn på regel.
    • eventName - Namn på händelse.
    • provider - Specifierar vilken provider som används.
    • profile - Anger vilken profile som skall användas.
    • minInstances - Minsta antalet fel innan eventet körs.
    • maxLimit - Max antal events innan loggningen upphör för aktuellt fel.
    • minInterval - Minsta tiden innan ett liknande fel loggas igen.
  • bufferModes
    • name - Namn på aktuell buffer.
    • maxBufferSize - Hur många events som kan lagras innan de flushas.
    • maxFlushSize - Max antal events för varje flush.
    • urgentFlushThreshold - Minst antal events som får finnas innan de flushas.
    • regularFlushInterval - Tidsintervall mellan varje flush.
    • urgentFlushInterval - Minsta tiden mellan varje flush.
    • maxBufferThreads - Maximalt antal trådar som får användas för flushen.
  • profiles
    • name - Namn på profil.
    • minInstances - Minsta antalet fel innan felet loggas.
    • maxLimit - Max antal fel innan den aktuella typen av fel slutar loggas.
    • minInterval - Minsta tiden mellan två loggningar av samma fel.

Ett exempel på hur detta kan ske när vi kör mot Event Viewer kan se ut på detta sätt:

   1:  <healthMonitoring enabled="true">
   2:      <eventMappings>
   3:          <clear/>
   4:          <add name="All Errors" type="System.Web.Management.WebBaseErrorEvent"/>
   5:      </eventMappings>
   6:      <providers>
   7:          <clear/>
   8:          <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider"/>
   9:      </providers>
  10:      <rules>
  11:          <clear/>
  12:          <add name="All Errors Default" eventName="All Errors" provider="EventLogProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"/>
  13:      </rules>
  14:  </healthMonitoring>

Med denna inställningen så kan vi se att vi först har en händelsemappning med namn "All Errors" och som är av typen WebBaseErrorEvent, sen har vi en provider med namn "EventLogProvider" och som är av typen "EventLogWebEventProvider", vilken sparar felen så vi kan hitta dem i Event Viewer. Den sista inställningen vi har är för reglerna, och där kan vi se att vi använder mappningen samt providern som vi har specifierat ovan, samt ställt in så att minst ett fel måste finnas innan det loggas, samt att vi inte har något intervall mellan felen, vilket gör att alla fel kommer att loggas här.

Om vi klickar på knappen på testsidan igen så kommer vi att få exakt samma resultat som innan, vi ser felmeddelandet och vi kan se felet i Event Viewer.

För att göra det lättare att visa upp felen som har uppstått så är det smidigt att använda en databas istället. Genom att först köra aspnet_regsql.exe så får vi tillgång till det som behövs i en SQL Server-databas.

För att lagra alla fel i SQL Server så räcker det med att ändra några rader i web.config, då klasserna finns inbyggda i .NET, samt att vi har skapat upp tabellerna.

Det första vi behöver göra är att skapa en ny provider som skall hämta en connectionstring och ange vilken typ av provider som vi skall använda oss utav. Det gör vi genom att under providers lägga till en ny rad för det:

   1:  <add connectionStringName="mySqlServer" buffer="false" name="SqlWebEventProvider" type="System.Web.Management.SqlWebEventProvider"/>

För att ASP.NET skall veta att det är just den providern vi vill använda oss utav så skall vi sedan ändra vår regel så att den använder SqlWebEventProvider istället för EventLogProvider.

Regeln bör se ut så här:

   1:  <add name="All Errors Default" eventName="All Errors" provider="SqlWebEventProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"/>

För att se om det fungerar nu så öppnar vi upp testsidan igen och klickar på knappen några gånger. Sen går vi in i databasen och ser vad tabellen aspnet_WebEvents_Events innehåller. Vi bör nu ha ett par rader med exakt samma felmeddelande som vi tidigare kunde se i Event Viewer:

3

Nästa steg är att skapa en egen provider där vi lagrar allt som vi själva vill.

No Comments