La gestion des exceptions est une composante cruciale de tout développement logiciel de qualité. En tant que développeur .NET, vous avez la possibilité d'utiliser des mécanismes puissants pour capturer, gérer et traiter les exceptions.
Comprendre comment gérer correctement les exceptions est essentiel pour garantir la robustesse de vos applications.
Cet article explore les principes fondamentaux de la gestion des exceptions en .NET et vous montre une façon de tout centraliser.
Une exception est une condition anormale ou une erreur qui se produit pendant l'exécution de votre application. Elle peut être causée par divers facteurs, tels qu'une division par zéro, une référence nulle (Les fameux NPE), une mauvaise syntaxe, une erreur d'E/S, une connexion réseau perdue, ou d'autres situations inattendues.
Sans une gestion appropriée, une exception non gérée peut provoquer la fermeture brutale de votre application.
Il existe deux grandes familles d’exceptions:
try-catch
en général. Elles dérivent toute de la classe System.Exception
.On va séparer ça en deux fichiers:
throw
lors de nos tests de non-null, par exemple :if (toto is not null)
{
// Do something
}
else
{
throw new CustomException("message")
OU
throw CustomException.Format(...)
OU
throw CustomException.Error400()
}
Voici un exemple d’énumération, elle contient certains types d’erreurs et peut retourner un message personnalisé à la suite.
public enum CustomErrorEnum
{
CUSTOM_400,
CUSTOM_400_WITH_CAUSE,
CUSTOM_401,
CUSTOM_401_WITH_CAUSE,
CUSTOM_403,
CUSTOM_403_WITH_CAUSE,
CUSTOM_404,
CUSTOM_404_WITH_CAUSE,
CUSTOM_500,
CUSTOM_500_WITH_CAUSE,
}
public static class CustomErrorEnumExtension
{
public static string ShowError(this CustomErrorEnum customErrorEnum)
{
return customErrorEnum switch
{
CustomErrorEnum.CUSTOM_400 => "Le paramètre est erroné.",
CustomErrorEnum.CUSTOM_400_WITH_CAUSE => "Le paramètre est erroné : {0}",
CustomErrorEnum.CUSTOM_401 => "Accès non autorisé.",
CustomErrorEnum.CUSTOM_401_WITH_CAUSE => "Accès non autorisé : {0}",
CustomErrorEnum.CUSTOM_403 => "Accès interdit",
CustomErrorEnum.CUSTOM_403_WITH_CAUSE => "Accès interdit : {0}",
CustomErrorEnum.CUSTOM_404 => "Aucun résultat trouvé.",
CustomErrorEnum.CUSTOM_404_WITH_CAUSE => "Aucun résultat trouvé: {0}",
CustomErrorEnum.CUSTOM_500 => "Une erreur serveur est survenue.",
CustomErrorEnum.CUSTOM_500_WITH_CAUSE => "Une erreur serveur est survenue : {0}",
_ => "",
};
}
}
Voici un exemple d’exception personnalisée, grâce à nos fonctions Format
nous allons pouvoir générer nos exceptions bien plus rapidement.
public class CustomException : Exception
{
public int? StatusCode { get; set; }
public CustomException(string? message) : base(message)
{
}
public CustomException(int statusCode, string? message) : base(message)
{
StatusCode = statusCode;
}
public CustomException(int statusCode, string? message, Exception? innerException) : base(message, innerException)
{
StatusCode = statusCode;
}
public CustomException(string? message, Exception innerException) : base(message, innerException)
{
}
public static CustomException Format(CustomErrorEnum CustomErrorEnum, params object[] values)
{
return new CustomException(string.Format(CustomErrorEnum.ShowError(), values));
}
public static CustomException Format(int statusCode, CustomErrorEnum CustomErrorEnum, params object[] values)
{
return new CustomException(statusCode, string.Format(CustomErrorEnum.ShowError(), values));
}
public static CustomException Format(Exception ex, CustomErrorEnum CustomErrorEnum, params object[] values)
{
return new CustomException(string.Format(CustomErrorEnum.ShowError(), values), ex);
}
public static CustomException Format(Exception ex, int statusCode, CustomErrorEnum CustomErrorEnum, params object[] values)
{
return new CustomException(statusCode, string.Format(CustomErrorEnum.ShowError(), values), ex);
}
public static CustomException Error400(params object[] values)
{
return values.Length == 0 ? new CustomException(StatusCodes.Status400BadRequest, string.Format(CustomErrorEnum.Custom_400.ShowError(), values)) : new CustomException(StatusCodes.Status400BadRequest, string.Format(CustomErrorEnum.Custom_400_WITH_CAUSE.ShowError(), values));
}
Vous pouvez inventer autant de méthodes que de code HTTP pour gérer chaque cas.
}
Il existe plusieurs façons de traiter nos exceptions.
La façon simple via try-catch
mais qui va nous faire répéter ce pattern autant de fois que l’on a de traitement d’exception, ou via un middleware qui va catch nos exceptions et surtout exceptions personnalisées pour les renvoyer proprement.
try-catch
La gestion des exceptions en .NET peut reposer sur les blocs try-catch
. Voici comment ils fonctionnent :
try
.try
, le flux de contrôle est immédiatement dirigé vers le bloc catch
.catch
pour gérer différents types d'exceptions.try
{
// Code susceptible de lancer une exception
}
catch (DivideByZeroException ex)
{
// Gérer la division par zéro ici
}
catch (Exception ex)
{
// Gérer toutes les autres exceptions ici
}
NB : on peut aussi rajouter un bloc finally
après notre dernier catch si l’on a besoin qu’un bloc de code soit exécuté peu importe si une exception est remontée ou non.
Pour ce faire, nous allons créer deux fichiers :
On a créé un fichier assez simple, mais on peut rajouter plus d’informations au besoin :
public class ErrorDetails
{
public int StatusCode { get; set; }
public string Message { get; set; }
public string InnerException { get; set; }
public string Source { get; set; }
public string StackTrace { get; set; }
}
Nous avons donc :
Dans ce fichier, nous allons avoir plusieurs choses :
RequestDelegate _next
qui va nous permettre d’encapsuler l’appel API dans un try-catch
.Et deux méthodes importantes :
Voici la première méthode qui permet d’encapsuler notre appel APIUne API est un programme permettant à deux applications distinctes de communiquer entre elles et d’échanger des données. :
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (CustomException ex)
{
await HandleExceptionAsync(httpContext, ex);
}
}
NB: Si on ne veut pas utiliser les exceptions personnalisées, on peut tout simplement catch une Exception lambda.
Voici la seconde méthode qui va permettre de transformer l’exception en flux d’erreurs lisibles par un utilisateur :
/// <summary>
/// Permet de transformer l'exception retournée en message d'erreur
/// </summary>
/// <param name="context"></param>
/// <param name="exception"></param>
/// <returns></returns>
private static async Task HandleExceptionAsync(HttpContext context, SdlvException exception)
{
HttpResponse response = context.Response;
response.ContentType = "application/json";
response.StatusCode = exception.StatusCode ?? StatusCodes.Status500InternalServerError;
ErrorDetails responseModel = new()
{
StatusCode = context.Response.StatusCode,
Message = exception.Message ?? "Internal Server Error",
InnerException = exception.InnerException?.Message,
Source = exception.Source,
StackTrace = exception.StackTrace
};
string result = JsonSerializer.Serialize(responseModel, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
await response.WriteAsync(result);
}
Maintenant que nous avons ces fichiers, il ne reste plus qu’à l’injecter !
On crée un nouvelle classe ExceptionMiddlewareExtensions qui va nous permettre de l’injecter directement dans notre application :
/// <summary>
/// Injecteur du middleware
/// </summary>
public static class ExceptionMiddlewareExtensions
{
/// <summary>
/// Permet d'injecter le middleware des exceptions
/// </summary>
/// <param name="app"></param>
public static void ConfigureCustomExceptionMiddleware(this IApplicationBuilder app)
{
app.UseMiddleware<ExceptionMiddleware>();
}
}
Il ne reste plus qu’à ajouter la ligne dans notre Program.cs :
app.ConfigureCustomExceptionMiddleware();
Et voilà ! Vous avez une gestion d’erreur centralisée !
En conclusion, la gestion des exceptions joue un rôle vital dans le développement logiciel de qualité, notamment pour les développeurs .NET. Les principes fondamentaux que nous avons explorés dans cet article vous aideront à mieux comprendre comment capturer, gérer et traiter les exceptions de manière efficace. En centralisant cette gestion, vous pouvez renforcer la robustesse de vos applications et offrir une meilleure expérience utilisateur.
Si vous avez des questions, des préoccupations ou si vous souhaitez en savoir plus sur la gestion des exceptions en .NET, n'hésitez pas à nous contacter. Notre équipe d'experts est là pour vous aider à perfectionner vos compétences en développement logiciel. Ne laissez pas les exceptions vous bloquer, faites un pas vers des applications plus fiables et performantes dès aujourd'hui. Contactez-nous pour en savoir plus !
Tuto : Vous souhaitez mettre en place une architecture propre et maintenable sur votre API .NET Core ? Vous êtes au bon endroit ! À la fin de cet article, vous aurez une API REST avec une architecture clean
Après avoir créé, structuré et posé les bases Clean Architecture .NET, il est temps de passer à l’API, pas à pas, c’est parti !
Comment optimiser le temps de mise à dispo d’un nouveau node dans un cluster JBOSS 7