Framework de gestion des exceptions

Un petit framework de gestion des exceptions orienté simplicité de mise en place et d'utilisation, plus particulièrement destiné au développement d'applications sur PDA (mais pas que). Vu 5062  fois

 

Le principe de la gestion des exceptions

 

Le principe de gérer les exceptions dans une application est essentiellement de gérer l’imprévu. En ce sens, toute erreur se produisant dans l’application devra :

  • être tracée pour pouvoir être analysée,
  • ne pas entrainer la fermeture brutale de l’application,
  • potentiellement interrompre et annuler l’ensemble de l’opération en cours,
  • dans certains cas informer l’utilisateur qu’une erreur s’est produite,
  • conserver une trace claire de l’exception pour permettre la résolution de l’anomalie.

 

Afin de s’assurer de gérer tous les imprévus, chaque méthode ayant la moindre chance d’émettre une exception doit implémenter une gestion des exceptions.

public void MaMethode(object arguments) 
{
try
{
// Execution de la méthode
}
catch (Exception exc)
{
// Gestion de l’exception exc
}
};

Les rares cas dans lesquels une gestion des exceptions n’est pas nécessaire dans une méthode sont les cas d’affectation simple, ou de retour d’une valeur définie :

public string Affecter(string param) 
{
this.valeur = param;
return true;
};

On voit déjà que s’il n’existe pas de gestion unifiée des exceptions, on va passer autant de temps à gérer les cas d’erreur qu’à implémenter les méthodes elles-mêmes, pour un résultat bien souvent inexploitable.

 

Afin d’automatiser la gestion des exceptions, on va définir notre propre type d’exception, ainsi qu’une classe de gestion mutualisée de l’ensemble des exceptions.

 


Définition d’une exception métier

 

Afin de manipuler une exception personnalisée, on définit notre propre type d’exception, dans laquelle on pourra inclure tous les éléments pertinents pour notre suivi des erreurs.

public class MobileException : Exception  
{
// Contenu de notre classe
}

Cette classe hérite de Exception pour pouvoir être manipulée comme une exception classique (à savoir permettre de faire un throw et être intercepté par un catch).

 

En variable privée de cette exception, on va typiquement définir les champs :

  • message (contenant le détail de l’exception),
  • code (pour catégoriser les exceptions si c’est pertinent, attention à la définition de l’ensemble des codes disponibles qui peut s’avérer laborieuse)
  • messageUtilisateur (si on souhaite afficher un message spécifique lorsque cette exception se produit)
  • etc.

Chacune de ces variables possède un accesseur correspondant, qui remplace celui de la classe mère Exception dans le cas du Message.

 

On peut également si besoin y ajouter des méthodes spécifiques à notre application, par exemple liées à des comportements spécifiques en fonction de la catégorie du code, ou tout autre comportement souhaité.


Création d’une classe de gestion des exceptions

 

Afin de mutualiser la manipulation des exceptions, on définit une classe qui sera chargée d’effectuer l’ensemble des traitements communs.

 

Cette classe devra être accessible depuis l’ensemble des méthodes de l’application, et on utilisera donc en général le pattern Singleton pour y accéder. Pour les applications modulaires (utilisant la réflexion), on donne accès à cette classe par l’intermédiaire du Manager.

 

public class GestionException
{
private static GestionException instance;
public static GestionException Singleton
{
get
{
if (GestionException.instance == null)
{
GestionException.instance = new GestionException();
}
return GestionException.instance;
}
}
// Méthodes de gestion des exceptions
}

Le rôle de cette classe est d’exposer l’ensemble des méthodes de gestion des exceptions, en laissant dans le catch des méthodes de l’application le moins de choses à faire possibles.

 

Le traitement des exceptions qui sera ici mutualisé consiste typiquement à tracer dans un fichier de log (voire dans certains cas en base de données) :

  • la date et l’heure de l’exception
  • la classe et le nom de la méthode dans laquelle elle s’est produite
  • le message de l’exception
  • la catégorie (le code) de l’exception

Le plus souvent, on ne souhaite tracer que la première méthode de notre application dans laquelle l’exception s’est produite, et non l’ensemble de la pile de méthodes (également appelée Stacktrace) qui alourdirait énormément la trace, ce qui n’est pas souhaitable dans l’environnement mobile.

 

On utilise donc notre classe typée d’exception pour déterminer si l’exception doit être tracée ou non. Si l’exception interceptée est de type MobileException, c’est qu’elle a déjà été traitée.


Créer une exception

 

La première méthode, mais paradoxalement la moins utilisée (car elle ne se base pas sur une exception interceptée, mais est générée dans des cas fonctionnels prédéfinis) va consister à créer une exception typée à partir de rien :

 

public MobileException CreerException(string message, string classe, string methode, int code, …) 
{
//TODO : Traitement de l’exception
return new MobileException(message, classe, code, …);
}
 

Transmettre une exception

 

Cette méthode est en théorie la plus utilisée. Elle consiste à recevoir une exception interceptée dans une méthode, et à la propager après l’avoir traité.

 

public void TransmettreException(Exception exception, string classe, string methode, int code, ...) 
{
if (exception is MobileException)
{
throw exception;
}
else
{
//TODO : Traitement de l’exception
throw new MobileException(exception.Message, classe, code, …);
}
}
 

Cette méthode sera utilisée dans toutes les méthodes de la manière suivante :

 

catch (Exception exc) 
{
GestionException.Singleton.TransmettreException(exc,

this.GetType().Name, "MaMethode()", Constante.CODE, …);
}

On constate que le code à dupliquer dans chaque méthode est minimaliste, et ne nécessite pas de se préoccuper de la nature de l’exception (native ou métier).

 

Tracer une exception

 

Cette variante de la méthode TransmettreException ne diffère qu’en ce qu’elle ne propage pas l’exception après l’avoir traitée :

 

public void TracerException(Exception exception, string classe, string methode, int code, ...) 
{
if (!(exception is MobileException))
{
//TODO : Traitement de l’exception
}
}

On est ainsi assuré d’avoir une trace de l’exception qu’elle se soit produite dans une sous-méthode ou dans la méthode elle-même, sans pour autant remonter l’exception à la méthode appelante.

 

Afficher une exception

 

Cette variante de la méthode TracerException ne diffère qu’en ce qu’elle affiche un message à l’utilisateur relatif à l’exception après l’avoir traitée :

 

public void AfficherException(Exception exception, string classe, string methode, int code, string messageUtilisateur, …) 
{
this.TracerException(exception, classe, methode);
MessageBox.Show(messageUtilisateur, "ERREUR", MessageBoxButtons.OK,
MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
}

 

Le détail du message à afficher est ici passé en paramètre de la méthode, mais il pourra également être définit en standard, ou fonction de la catégorie (code) de l’exception initiale.

 

Le choix de la définition du message à afficher est fonction du niveau d’information que l’on souhaite fournir à l’utilisateur sur les exceptions qui se produisent.


Règles d’utilisation

Chacune des méthodes exposées par la classe de gestion des exceptions s’utilise dans des cas bien précis.

 

On utilisera la méthode CreerException dans les cas suivants : 

  • Cas fonctionnel prévu lors de la réalisation mais incorrect et qui nécessite l’émission d’une exception pour interrompre le traitement.

On utilisera la méthode AfficherException dans les cas suivants :

  • Méthode de gestion d’un évènement de type Click ou Load pour laquelle :
    • la propagation d’une exception remonterait jusqu’au système, et ne serait plus gérée (risque de fermeture brutale de l’application)
    • on souhaite avertir l’utilisateur qu’une exception s’est produite et a interrompue le traitement

On utilisera la méthode TracerException dans les cas suivants :

  • Méthode de gestion d’un évènement ou méthode principale d’un thread secondaire, pour laquelle :
    • la propagation d’une exception remonterait jusqu’au système, et ne serait plus gérée (risque de fermeture brutale de l’application)
    • on ne souhaite pas avertir l’utilisateur qu’une erreur s’est produite (gestion silencieuse de passage de Focus qui pourrait entrainer des boucles, traitements en tâche de fond, etc.)
  • Traitements non critiques pour lesquels l’obtention d’une exception ne justifie pas l’interruption complète du traitement.

On utilisera la méthode TransmettreException dans tous les autres cas, à savoir :

  • Méthode de l’application qui est appelée par une autre méthode de l’application à laquelle on souhaite propager l’exception après avoir tracer le fait que l’exception s’est produite à ce niveau.

Bon code !


 

Publié le  23/10/2008
Auteur:  Patrick A

 

Commentaires

Posté le : 28/10/2008 Par : wpilon

Bonjour.

Une petite question : tu ne perd pas la StackTrace en faisant le 'throw exception;' dans la méthode TransmettreException ?

Posté le : 30/10/2008 Par : Patrick A

Bonjour,

Effectivement, à ce stade la StackTrace est supprimée.

Ca ne devrait pas être un problème dans la mesure où l'exception est traitée (et tracée) lors de la création de la MobileException (et à ce stade la StackTrace est encore présente). Le throw de MobileException ne sert plus qu'à terminer le traitement et atteindre un TracerException ou un AfficherException dans la méthode principale. Il ne devrait plus y avoir à ce stade de traitement de l'exception.

Si on souhaite connaitre la StackTrace jusqu'à la méthode appelante (click par exemple) il faut modifier le framework, mais en pratique ça n'apporte que rarement de valeur ajoutée par rapport à la complexité engendrée (et attention à la taille des traces si on utilise la StackTrace, particulièrement sur du developpement mobile).

Si vous souhaitez ajouter un commentaire vous devez être authentifié.

 

ASP-PHP.NET  C²I  ClubVSTS  CodePPC  CodeS-SourceS  Dotnet-News.com  Tech Head Brothers 

Dotnet-Project.com© tous droits réservés
Webmaster Aleks. Ont collaboré à l'aboutissement de ce projet :
CodeS-SourceS.com, ASP-PHP.Net, DotNet-FR.org, C2i.fr, Newsletter ASP.NET.