ASPNL logo (1 kb)
zaterdag 17 mei 2008




Microsoft MVP

.NET Codewise Community
<< vorige | overzicht | volgende >>

Fouten registreren in ASP.NET

Door Michiel van Otegem
1 augustus 2006

Een webapplicatie wordt potentieel door vele gebruikers bezocht. Dat daarbij af en toe fouten ontstaan is haast onvermijdelijk. Met zoveel gebruikers wordt het echter lastig om te achterhalen wat er fout gaat en waarom, om over het kunnen reconstrueren van de fouten nog maar te zwijgen. Het is daarom uiterst belangrijk om fouten in een log op te slaan, zodat er later een analyse gemaakt kan worden, en structurele fouten opgelost kunnen worden.

In het vorige artikel uit deze serie heb ik foutafhandeling en opsporing binnen een pagina besproken. Ook heb ik laten zien hoe je eenvoudig de configuratie in kunt stellen om te verwijzen naar foutafhandelingspagina's, op basis van de verschillende fouten die kunnen optreden. In een applicatie met veel gebruikers is het echter niet gezegd dat een fout in een pagina de volgende keer ook optreedt, dat hangt sterk van de situatie af. Wil je structurele fouten opsporen en oplossen, dan moet dus vastgelegd worden wat er fout gaat. In ASP kan dit normaal gezien alleen in een database of apart bestand, en dat is ronduit onhandig. Voor een beheerder is het veel makkelijker als alle logs via hetzelfde mechanisme toegankelijk zijn. Precies om die reden was Windows NT al uitgerust met de Event Log, en is dat ook nu een belangrijk gereedschap voor het gezond houden van de server. In ASP was de Event Log echter niet aan te schrijven zonder speciaal COM component. De Event Log is in het .NET Framework beschikbaar via de System.Diagnostics namespace, en net als alle andere applicaties heeft ASP.NET hier gewoon toegang toe. Ontwikkelaars kunnen er dus nu voor zorgen dat fouten netjes in de Event Log worden opgeslagen, en daar is eigenlijk helemaal niet zoveel moeite voor nodig, zoals je kunt zien in Figuur 1.

 1: <%@ Page Language="VB" %>
 2: <%@ Import Namespace="System.Diagnostics" %>
 3: <script runat="server">
 4:   Sub Page_Load()
 5:     Dim strLogTekst = "Event demo " & DateTime.Now.ToString()
 6:     Dim ID As Integer = 50
 7:     
 8:     'Log instellen
 9:     Dim el As EventLog = New EventLog()
10:     el.MachineName = "."
11:     el.Source = "EventLogDemo"
12:     el.Log = "DemoLog"
13:   
14:     'Log maken als het nog niet bestaat<
15:     If Not EventLog.SourceExists(el.Source) Then
16:         el.CreateEventSource(el.Source, el.Log)
17:     End If
18:     
19:     'Naar log schrijven
20:     el.WriteEntry(strLogTekst, EventLogEntryType.Information, ID)       
21:     lblLog.Text = strLogTekst
22:   End Sub
23: </script>
24: <html>
25: <body>
26:   Log tekst:
27:   <asp:label id="lblLog" runat="server"/>
28: </body>
29: </html>
Figuur 1, Pagina die naar de Event Log schrijft

De pagina in figuur 1 geeft als resultaat in de browser de tekst die naar de Event Log geschreven is. Er wordt hier dus moedwillig naar de Event Log geschreven, zonder dat er een fout optreedt. Dat kan handig zijn voor een audit log, bijvoorbeeld van succesvol inloggen. Op de tweede regel wordt de System.Diagnostics Namespace geïmporteerd, zodat we de classes kunnen gebruiken die nodig zijn als we naar de Event Log willen schrijven. Het eerste wat de code doet is een tekst maken die naar de Event Log geschreven wordt, en een bijbehorende foutcode. De tekst mag van alles zijn, maar is in principe bedoeld voor menselijke lezers, dus het is handig om hierin een goede beschrijving van de fout neer te zetten. De foutcode is in principe bedoeld voor andere programma's, bijvoorbeeld om de Event Log te analyseren. Ook de foutcode mag je zelf bedenken, maar het is handig om dit volgens bepaalde regels te doen, en eventueel om ze van te voren vast te leggen. Het tweede argument van de functie WriteEntry bepaalt wat voor soort boodschap er naar de Event Log geschreven wordt. De soort kan één van de volgende mogelijkheden van EventLogEntryType zijn:

  • Error
  • Warning
  • FailureAudit
  • SuccesAudit
  • Information

Error gebruik je natuurlijk voor fouten, terwijl een Warning meer bedoeld is om aan te geven dat er potentieel problemen kunnen ontstaan. FailureAudit en SuccesAudit wordt gebruikt voor gebeurtenissen die te maken hebben met de beveiliging, over het algemeen het succesvol of onsuccesvol inloggen op het systeem. Information is voor puur informatieve doeleinden, bijvoorbeeld het starten of stoppen van een applicatie.

Nu je weet hoe je naar de Event Log kunt schrijven, is de volgende stap ervoor zorgen dat je fouten die je kunt voorzien goed afhandelt. Dat wil zeggen dat je de juiste actie onderneemt als de fout optreedt, en vervolgens netjes opruimt. Als je dit niet doet, kan de server op langere termijn problemen ondervinden van fouten die op zich zelf onschuldig zijn. Operaties op een database kunnen bijvoorbeeld mis gaan. Het daarna niet sluiten van de databaseverbinding kan nare gevolgen hebben, en het is dus zaak dit soort problemen te voorkomen. In het .NET Framework, en dus in ASP.NET, hebben alle talen dezelfde mechanismen om fouten af te handelen. Dit gaat via het zogenaamde try-catch principe, waarin een blok code "geprobeerd" wordt en bij het optreden van een fout code in werking treedt die de fout afhandelt. Als laatste kan er ook nog code uitgevoerd worden ongeacht het resultaat. Figuur 2 laat code zien die gebruik maakt van dit principe.

 1: <%@ Page Language="VB" %>
 2: <%@ import Namespace="System.IO" %>
 3: <%@ import Namespace="System.Diagnostics" %>
 4: <script runat="server">
 5:   Sub Page_Load()
 6:     Try
 7:       Dim sr As New StreamReader("c:\bestaatniet.txt")
 8:       lblFile.Text = sr.ReadToEnd()
 9:       sr.Close()
10:     Catch ex As FileNotFoundException
11:       Dim strLogTekst = "File not Found"
12:       Dim ID As Integer = 50
13:     
14:       'Log instellen
15:       Dim el As EventLog = New EventLog()
16:       el.MachineName = "."
17:       el.Source = "EventLogDemo"
18:       el.Log = "DemoLog"
19:     
20:       'Log maken als het nog niet bestaat
21:       If Not EventLog.SourceExists(el.Source) Then
22:           el.CreateEventSource(el.Source, el.Log)
23:       End If
24:     
25:       'Naar log schrijven
26:       el.WriteEntry(strLogTekst, EventLogEntryType.Information, ID)
27:       lblFile.Text = "Error: File not Found"
28:     Finally
29:       'Hier eventueel opruimen, nu niet nodig
30:     End Try
31:   End Sub
32: </script>
33: <html>
34: <body>
35:   Log tekst:
36:   <asp:label id="lblFile" runat="server"/>
37: </body>
38: </html>
Figuur 2, Pagina met Try-Catch constructie

In de pagina in figuur 2 wordt geprobeerd een bestand te openen en de inhoud daarvan in lblFile te zetten. Als het bestand niet bestaat, wordt dat aan de Event Log gemeld volgens hetzelfde principe als in figuur 1. Ook wordt er nog een bericht naar lblFile geschreven. In het Finally blok staat in dit geval niets, maar hier zou je eventueel kunnen opruimen na een fout. Het handige van op deze manier in de pagina een fout afhandelen, is dat je de gebruiker niet persé op de hoogte hoeft te stellen van de fout. Als je alternatieve actie kunt nemen, kun je het resultaat daarvan laten zien. Het probleem met sommige fouten is echter dat je ze niet kunt voorzien. Ze gebeuren gewoon, omdat er ineens iets onverwachts veranderd is. Dat soort fouten zijn vrijwel niet mooi af te handelen, en in dat geval zul je dus moeten verwijzen naar een standaard foutpagina. Je wil echter wel dat dit soort fouten worden geregistreerd in de Event Log, want dan weet je later dat er wel iets fout is gegaan, en kun je eventueel actie ondernemen. Voordat ASP.NET een gebruiker doorverwijst naar de opgegeven foutpagina, zal het eerst Application_Error in het global.asax bestand uitvoeren. Dit bestand bevat gebeurteniscode voor allerlei gebeurtenissen die buiten een pagina vallen. Application_Error is specifiek bedoeld om fouten af te handelen. Figuur 3 laat zien hoe dit eruit ziet.

 1: <%@ Application language="VB" %>
 2: <script runat="server">
 3:   Sub Application_Error(Sender As Object, E As EventArgs) 
 4:     Dim ex As Exception = Server.GetLastError.GetBaseException()
 5:     Dim strMsg As String
 6:     Dim ID As Integer = 50
 7:    
 8:     strMsg = "MESSAGE=" & ex.Message & _
 9:              "\nSOURCE=" & ex.Source & _
10:              "\nFORM=" & Request.Form.ToString() & _
11:              "\nQS=" & Request.QueryString.ToString()
12:  
13:     'Log instellen
14:     Dim el As EventLog = New EventLog()
15:     el.MachineName = "."
16:     el.Source = "GlobalLogDemo"
17:     el.Log = "DemoLog"
18:    
19:     'Log maken als het nog niet bestaat
20:     If Not EventLog.SourceExists(el.Source) Then
21:       el.CreateEventSource(el.Source, el.Log)
22:     End If
23:     
24:     'Naar log schrijven
25:     el.WriteEntry(strLogTekst, EventLogEntryType.Information, ID)
26:   End Sub
27: </script>
Figuur 3, Global.asax bestand voor het centraal afhandelen van fouten

In figuur 3 is het meeste al bekend. Wat anders is, is de opbouw van de foutboodschap. Omdat de Event Log maar beperkte informatie opslaat, is het zaak om de boodschap zo uitgebreid mogelijk te maken. In dit geval wordt daarom de boodschap van de oorspronkelijke fout en de bron daarvan meegestuurd in de boodschap. Ook worden de gegevens die de browser meegestuurd heeft, zowel die uit een formulier als in de URL, bij de aanvraag meegestuurd. Die eerste twee gegevens kun je ophalen door het Exception (fout) object op te vragen van de laatst voorgekomen fout (de fout die er voor heeft gezorgd dat deze code wordt uitgevoerd). De gegevens uit het formulier en de URL moet je los opvragen.

Conclusie

Foutafhandeling is een belangrijk aspect van elke applicatie. Met behulp van standaard functies in het .NET Framework en ASP.NET, is het makkelijk om fouten af te handelen en zonodig te registreren. Het is vervolgens aan de systeembeheerder en de ontwikkelaar samen om de gegevens die daardoor beschikbaar komen te gebruiken om de applicatie en de server gezond te houden.
De code in dit artikel kun je downloaden via de Windows & .NET Magazine website. Hierbij zit ook een pagina om de Event Log via het web uit te lezen (vanwege de complexiteit en lengte hier niet besproken).

Dit artikel is eerder verschenen in Windows & .NET Magazine Benelux, november 2002 (huidige naam NetOpus)

<< vorige | ^ naar boven | overzicht | volgende >>
copyright 2000-2007 ASPNL