Felhantering på applikationsnivå
Förord
Alla har vi väl råkat ut för att ett program genererat ett fel som det inte kan hanteras och stängs sedan ner. I de senaste versionerna av Windows kommer det numera upp en ruta som ger dig som användare möjligheten att skicka in en felrapport till Microsoft som de kan använda för att förbättra sin produkt (något som man förövrigt bör använda sig av då det hjälper oss alla genom att Microsoft kan identifiera fel och släppa patchar fortare).Innehåll
»»
»
Vore det inte trevligt om du eller ditt företag kunde använda er av samma teknik för att t.ex. be användaren av ert program att skicka in en felrapport, eller kanske använda tekniken för att implementera en centraliserad felhantering?
Hur skall man som utvecklare kunna fånga alla fel som inte hanteras i programmet? Som tur är har Microsoft gett oss precis den ingången till problem som vi behöver. Vi kan nämligen använda oss av ThreadException händelsen som körs när ett fel som inte hanteras upptäcks.
Allt vi behöver gör är att skapa en egen klass som hanterar denna händelse. I denna klassen kommer vi att lägga den kod som skall köras, vilket i vårt fall är att skapa och visa ett formulär där användaren får möjlighet att skicka in en felrapport.
Man skulle även kunna tänka sig att man loggade felet till event loggen, eller att man angör om felet är så pass alvarligt att programmet måste stängas. En stor fördel med det är att man t.ex..kan spara undan ändras information som ännu inte sparats och sen stänga ner applikationen. På så sätt blir man inte av med information när ett fel som inte hanterats inträffat.
Vad behövs då för att registrera sig som lyssnare på ThreadException händelsen? Vi börjar med att skapa en helt vanlig klass som vi kallar GlobalExceptionHandler.
[C#]
[VB.NET]
Då ThreadException händelsen förväntar sig att alla lyssnar implementerar en metod som har samma signatur (returvärde och parametrar) som ThreadExceptionEventHandler delagaten, så lägger vi till en egen metod med namnet OnThreadException.
[C#]
[VB.NET]
Metoden är nu inlagd I klassen och innehållet lite kod för att visa ett enkelt formulär som informerar användaren om att fel inträffade. Användaren presenteras också med möjligheten att skicka en felrapport till oss (simuleras med en dialogruta). Oavsett vilket val som användaren väljer så kommer applikationen att avslutas efteråt.
Som en av parametrarna till metoden skickas det in ett ThreadExceptionEventArgs objekt som innehåller åtkomstmetod som heter Exception, vilken ger dig tillgång till det fel som inträffade. Genom att ha tillgång till det inträffade felet så kan man välja att reagera olika.
Det sista som måste göras är att informera applikationen om att vår felhanterare finns tillgänglig för användning om det skulle behövas. För att göra detta registreras klassen som en hanterare i Main metoden (VB.NET programmerare måste använda sig av Sub Main() för att starta programmet och inte direkt starta ett formulär).
[C#]
[VB.NET]
Det är allt som behövs för att kunna börja hantera fel på applikationsnivå. Jag vill påpeka att detta skall inte användas för att ersätta lokal felhantering i kod. Man skall försöka fånga fel där de inträffar då man kan hantera dem med kännedom om var felet inträffade. Fullständig källkod, med både C# och VB.NET exempel, som visar hur man använder sig av detta finns att ladda ner i programarkivet Programarkivet:Felhantering på applikationsnivå
Hur skall man som utvecklare kunna fånga alla fel som inte hanteras i programmet? Som tur är har Microsoft gett oss precis den ingången till problem som vi behöver. Vi kan nämligen använda oss av ThreadException händelsen som körs när ett fel som inte hanteras upptäcks.
Allt vi behöver gör är att skapa en egen klass som hanterar denna händelse. I denna klassen kommer vi att lägga den kod som skall köras, vilket i vårt fall är att skapa och visa ett formulär där användaren får möjlighet att skicka in en felrapport.
Man skulle även kunna tänka sig att man loggade felet till event loggen, eller att man angör om felet är så pass alvarligt att programmet måste stängas. En stor fördel med det är att man t.ex..kan spara undan ändras information som ännu inte sparats och sen stänga ner applikationen. På så sätt blir man inte av med information när ett fel som inte hanterats inträffat.
ExceptionHandler
Vad behövs då för att registrera sig som lyssnare på ThreadException händelsen? Vi börjar med att skapa en helt vanlig klass som vi kallar GlobalExceptionHandler.[C#]
using System;
using System.Threading;
public class GlobalExceptionHandler
{
public GlobalExceptionHandler()
{
}
}
[VB.NET]
Imports System
Imports System.Threading
Public Class GlobalExceptionHandler
Public Sub New()
End Sub
End Class
Eventhandler
Då ThreadException händelsen förväntar sig att alla lyssnar implementerar en metod som har samma signatur (returvärde och parametrar) som ThreadExceptionEventHandler delagaten, så lägger vi till en egen metod med namnet OnThreadException.[C#]
using System;
using System.Threading;
public class GlobalExceptionHandler
{
public GlobalExceptionHandler()
{
}
// Detta är metoden som anropas när ett ohanterat
// fel inträffat. Här kan du placera den logik som
// du vill skall köras.
public void OnThreadException(object sender, ThreadExceptionEventArgs threadEx)
{
ExceptionForm form =
new ExceptionForm();
form.ShowDialog();
}
}
[VB.NET]
Imports System
Imports System.Threading
Public Class GlobalExceptionHandler
Public Sub New()
End Sub
' Detta är metoden som anropas när ett ohanterat
' fel inträffat. Här kan du placera den logik som
' du vill skall köras.
Public Sub OnThreadException(ByVal Sender As Object, ByVal ThreadEx As ThreadExceptionEventArgs)
Dim Form As ExceptionForm
Form = New ExceptionForm
Form.ShowDialog()
End Sub
End Class
Metoden är nu inlagd I klassen och innehållet lite kod för att visa ett enkelt formulär som informerar användaren om att fel inträffade. Användaren presenteras också med möjligheten att skicka en felrapport till oss (simuleras med en dialogruta). Oavsett vilket val som användaren väljer så kommer applikationen att avslutas efteråt.
Som en av parametrarna till metoden skickas det in ett ThreadExceptionEventArgs objekt som innehåller åtkomstmetod som heter Exception, vilken ger dig tillgång till det fel som inträffade. Genom att ha tillgång till det inträffade felet så kan man välja att reagera olika.
Felhantering
Det sista som måste göras är att informera applikationen om att vår felhanterare finns tillgänglig för användning om det skulle behövas. För att göra detta registreras klassen som en hanterare i Main metoden (VB.NET programmerare måste använda sig av Sub Main() för att starta programmet och inte direkt starta ett formulär).[C#]
static void Main()
{
Application.EnableVisualStyles();
// Skapa ett objekt av klassen som
// innehåller metoden för felhantering.
GlobalExceptionHandler handler =
new GlobalExceptionHandler();
// Registrera objektets metod som
// felhanterare.
Application.ThreadException +=
new ThreadExceptionEventHandler(handler.OnThreadException);
// Starta och visa programmet.
Application.Run(new Form1());
}
[VB.NET]
Module Main
Sub Main()
Application.EnableVisualStyles()
' Skapa ett objekt av klassen som
' innehåller metoden för felhantering.
Dim Handler As GlobalExceptionHandler
Handler = New GlobalExceptionHandler
' Registrera objektets metod som
' felhanterare.
AddHandler Application.ThreadException, AddressOf Handler.OnThreadException
' Starta och visa programmet.
Application.Run(New Form1)
End Sub
End Module
Det är allt som behövs för att kunna börja hantera fel på applikationsnivå. Jag vill påpeka att detta skall inte användas för att ersätta lokal felhantering i kod. Man skall försöka fånga fel där de inträffar då man kan hantera dem med kännedom om var felet inträffade. Fullständig källkod, med både C# och VB.NET exempel, som visar hur man använder sig av detta finns att ladda ner i programarkivet Programarkivet:Felhantering på applikationsnivå
staffan sjöstedt
Tack för det Andreas Jag vill bara tillägga att Application.ThreadException bara fångar upp undantag i Managed Code och i Windows Forms-applikationer. Om man gör en console-app eller blandar in icke managed code ( t ex COM ) så måste det till ytterligare en hanterare. AppDomain.CurrentDomain.UnhandledException är den händelse som slängs vid ofångade undantag. Lyssaren ska ha följade utseende: static void UnhandledExceptionsHandler( object sender, UnhandledExceptionEventArgs e ){...} En implementation av denna skulle kunna se ut som:
static void UnhandledExceptionsHandler( object sender, UnhandledExceptionEventArgs e ) { string info; Exception ex = e.ExceptionObject as Exception; if( ex != null ) // CLS exception info = ex.Message; else // icke CLS execption - COM kanske? info = string.Format( "Non CLS exception: Type={0}, String={1}", e.ExceptionObject.GetType(), e.ExceptionObject.ToString() ); // ... gör ngt med info .... }
Alltså, om UnhandledExceptionEventArgs e har attributet ExceptionObject och detta är av typen Exception så är det ett "vanligt" managed code undantag, som hanteras enligt Anderas artikel ovan, annars kommer det från icke managed code och kräver lite specialbehandling. Man kan läsa mer i boken Applied Microsoft .NET Framework programming av Jeffrey Richter (varifrån jag fått mina kunskaper i ämnet) En riktigt bra bok för den som kommit en liten bit in i .NET. PS. Eftersom jag inte är så slängd i VB så får ni stå ut med c# hellre än att det bli konstigheter. DS