Comment gérer les erreurs dans les applications API minimales
Remarque
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.
Avertissement
Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.
Important
Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.
Pour la version actuelle, consultez la version .NET 9 de cet article.
Avec des contributions de David Acker
Cet article explique comment gérer les erreurs dans les applications API minimales. Pour plus d’informations sur la gestion des erreurs d’API basées sur contrôleur, consultez Gérer les erreurs dans ASP.NET Core et Gérer les erreurs d’API web basées sur contrôleur ASP.NET Core.
Exceptions
Dans une application API minimale, il existe deux mécanismes centralisés intégrés différents pour gérer les exceptions non gérées :
- Intergiciel de page d’exception de développeur (pour une utilisation dans l’environnement de développement uniquement.)
- Intergiciel du gestionnaire d’exceptions
Cette section fait référence à l’exemple d’application suivante pour illustrer des méthodes de gestion d’exceptions d’API minimale. Elle lève une exception lorsque le point de terminaison /exception
est demandé :
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/exception", () =>
{
throw new InvalidOperationException("Sample Exception");
});
app.MapGet("/", () => "Test by calling /exception");
app.Run();
Page d’exceptions du développeur
La Page d’exception du développeur affiche des informations détaillées sur les exceptions des requêtes non prises en charge. Il utilise DeveloperExceptionPageMiddleware pour capturer des exceptions synchrones et asynchrones à partir du pipeline HTTP et pour générer des réponses d’erreur. La page d’exception du développeur s’exécute au début du pipeline intergiciel, de manière qu’elle puisse intercepter les exceptions non prises en charge levées dans l’intergiciel qui suit.
Les applications ASP.NET Core activent la page d’exception du développeur par défaut en présence des deux éléments suivants :
- Exécution dans l’environnement de développement.
- L’application a été créée avec les modèles actuels, c’est-à-dire à l’aide de WebApplication.CreateBuilder.
Les applications créées à l’aide de modèles antérieurs, c’est-à-dire à l’aide de WebHost.CreateDefaultBuilder, peuvent activer la page d’exception de développeur en appelant app.UseDeveloperExceptionPage
.
Avertissement
Activez la Page d’exception de développeur uniquement quand l’application est en cours d’exécution dans l’environnement de développement. Il n’est pas souhaitable de partager publiquement des informations détaillées sur les exceptions quand l’application s’exécute en production. Pour plus d’informations sur la configuration selon l’environnement, consultez Utiliser plusieurs environnements dans ASP.NET Core.
La page d’exception du développeur peut inclure les informations suivantes sur l’exception et la requête :
- Trace de pile
- Paramètres de la chaîne de requête, le cas échéant
- Cookies (le cas échéant)
- En-têtes
- Métadonnées du point de terminaison, le cas échéant
Il n’est pas garanti que la page d’exception du développeur fournisse des informations. Utilisez la journalisation pour obtenir des informations complètes sur l’erreur.
L’image suivante montre un exemple de page d’exception de développeur avec animation pour afficher les onglets et les informations affichées :
En réponse à une demande avec un en-tête Accept: text/plain
, la page d’exception du développeur retourne du texte brut au lieu de HTML. Par exemple :
Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
at lambda_method1(Closure, Object, HttpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f
Pour afficher la page d’exception de développeur :
- Exécutez l’exemple d’application dans l’environnement de développement.
- Accédez au point de terminaison
/exception
.
Gestionnaire d’exceptions
Dans les environnements non de développement, utilisez l’intergiciel du gestionnaire d’exceptions pour produire une charge utile d’erreur. Pour configurer le Exception Handler Middleware
, appelez UseExceptionHandler.
Par exemple, le code suivant modifie l’application pour répondre avec une charge utile conforme au RFC 7807au client. Pour plus d’informations, consultez la section Détails du problème plus loin dans cet article.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseExceptionHandler(exceptionHandlerApp
=> exceptionHandlerApp.Run(async context
=> await Results.Problem()
.ExecuteAsync(context)));
app.MapGet("/exception", () =>
{
throw new InvalidOperationException("Sample Exception");
});
app.MapGet("/", () => "Test by calling /exception");
app.Run();
Réponses d’erreur client et serveur
Considérez l’application API minimale suivante.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));
app.MapGet("/", () => "Test by calling /users/{id:int}");
app.Run();
public record User(int Id);
Le point de terminaison/users
produit 200 OK
avec une json
représentation de User
quand id
est supérieure à 0
, sinon un code d’état 400 BAD REQUEST
sans corps de réponse. Pour plus d’informations sur la création d’une réponse, consultez Créer des réponses dans les applications API minimales.
Le Status Code Pages middleware
peut être configuré pour produire un contenu de corps commun, lorsqu’il est vide, pour toutes les réponses du client HTTP (499
-400
) ou du serveur (500
-599
). L’intergiciel est configuré en appelant la méthode d’extension UseStatusCodePages .
Par exemple, l’exemple suivant modifie l’application pour répondre avec une charge utile conforme au RFC 7807 au client pour toutes les réponses client et serveur, y compris les erreurs de routage (par exemple, 404 NOT FOUND
). Pour plus d’informations, consultez la section Détails du problème.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStatusCodePages(async statusCodeContext
=> await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
.ExecuteAsync(statusCodeContext.HttpContext));
app.MapGet("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
app.MapGet("/", () => "Test by calling /users/{id:int}");
app.Run();
public record User(int Id);
Détails du problème
Les détails du problème ne sont pas le seul format de réponse à décrire une erreur d’API HTTP. Toutefois, ils sont couramment utilisés pour signaler des erreurs pour les API HTTP.
Le service des détails du problème implémente l’interface IProblemDetailsService, qui prend en charge la création de détails de problème dans ASP.NET Core. La méthode d’extension AddProblemDetails(IServiceCollection) sur IServiceCollection enregistre l’implémentation IProblemDetailsService
par défaut.
Dans les applications ASP.NET Core, l’intergiciel suivant génère des réponses HTTP sur les détails de problème lorsque AddProblemDetails
est appelé, sauf si l’en-tête HTTP de requêteAccept
n’inclut pas l’un des types de contenu pris en charge par le IProblemDetailsWriter inscrit (par défaut : application/json
) :
- ExceptionHandlerMiddleware : génère une réponse sur les détails du problème lorsqu’un gestionnaire personnalisé n’est pas défini.
- StatusCodePagesMiddleware : génère une réponse de détails de problème par défaut.
- DeveloperExceptionPageMiddleware : génère une réponse sur les détails du problème lors du développement lorsque l’en-tête HTTP de la requête
Accept
n’inclut pastext/html
.
Les applications API minimales peuvent être configurées pour générer une réponse de détails sur le problème pour toutes les réponses d’erreur client et serveur HTTP qui n’ont pas encore de contenu de corps à l’aide de la méthode d’extension AddProblemDetails
.
Le code suivant configure l’application pour générer les détails du problème :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
app.MapGet("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));
app.MapGet("/", () => "Test by calling /users/{id:int}");
app.Run();
public record User(int Id);
Pour plus d’informations sur l’utilisation de AddProblemDetails
, consultez Détails du problème
IProblemDetailsService de secours
Dans le code suivant, httpContext.Response.WriteAsync("Fallback: An error occurred.")
retourne une erreur si l’implémentation IProblemDetailsService ne peut pas générer un ProblemDetails :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async httpContext =>
{
var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
if (pds == null
|| !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
{
// Fallback behavior
await httpContext.Response.WriteAsync("Fallback: An error occurred.");
}
});
});
app.MapGet("/exception", () =>
{
throw new InvalidOperationException("Sample Exception");
});
app.MapGet("/", () => "Test by calling /exception");
app.Run();
Le code précédent :
- Écrit un message d’erreur avec le code de secours, si le
problemDetailsService
ne parvient pas à écrire unProblemDetails
. Par exemple, un point de terminaison dans lequel l’en-tête de demande Accepter spécifie un type de média non pris en charge parDefaulProblemDetailsWriter
. - Utilise l’intergiciel gestionnaire d’exceptions.
L’exemple suivant est semblable au précédent, sauf qu’il appelle Status Code Pages middleware
.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseStatusCodePages(statusCodeHandlerApp =>
{
statusCodeHandlerApp.Run(async httpContext =>
{
var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
if (pds == null
|| !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
{
// Fallback behavior
await httpContext.Response.WriteAsync("Fallback: An error occurred.");
}
});
});
app.MapGet("/users/{id:int}", (int id) =>
{
return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});
app.MapGet("/", () => "Test by calling /users/{id:int}");
app.Run();
public record User(int Id);
Cet article explique comment gérer les erreurs dans les applications API minimales.
Exceptions
Dans une application API minimale, il existe deux mécanismes centralisés intégrés différents pour gérer les exceptions non gérées :
- Intergiciel de page d’exception de développeur (pour une utilisation dans l’environnement de développement uniquement.)
- Intergiciel du gestionnaire d’exceptions
Cette section fait référence à l’application API minimale suivante pour illustrer les méthodes de gestion des exceptions. Elle lève une exception lorsque le point de terminaison /exception
est demandé :
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample Exception"); });
app.Run();
Page d’exceptions du développeur
La page d’exception du développeur affiche des traces détaillées de pile pour les erreurs de serveur. Il utilise DeveloperExceptionPageMiddleware pour capturer des exceptions synchrones et asynchrones à partir du pipeline HTTP et pour générer des réponses d’erreur.
ASP.NET Applications Core activent la page d’exception de développeur par défaut lorsque les deux :
- Exécution dans l’environnement de développement.
- L’application utilise WebApplication.CreateBuilder.
Pour plus d’informations sur la configuration du middleware, consultez Middleware dans les applications API minimales.
À l’aide de l’application API minimale précédente, lorsque le Developer Exception Page
détecte une exception non gérée, il génère une réponse de texte brut par défaut similaire à l’exemple suivant :
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked
System.InvalidOperationException: Sample Exception
at Program.<>c.<<Main>$>b__0_1() in ....:line 17
at lambda_method2(Closure, Object, HttpContext)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br
Warning
Activez la Page d’exception de développeur uniquement quand l’application est en cours d’exécution dans l’environnement de développement. Il n’est pas souhaitable de partager publiquement des informations détaillées sur les exceptions quand l’application s’exécute en production. Pour plus d’informations sur la configuration selon l’environnement, consultez Utiliser plusieurs environnements dans ASP.NET Core.
Gestionnaire d’exceptions
Dans les environnements non de développement, utilisez l’intergiciel du gestionnaire d’exceptions pour produire une charge utile d’erreur. Pour configurer le Exception Handler Middleware
, appelez UseExceptionHandler.
Par exemple, le code suivant modifie l’application pour répondre avec une charge utile conforme au RFC 7807au client. Pour plus d’informations, consultez la section Détails du problème.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseExceptionHandler(exceptionHandlerApp
=> exceptionHandlerApp.Run(async context
=> await Results.Problem()
.ExecuteAsync(context)));
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample Exception"); });
app.Run();
Réponses d’erreur client et serveur
Considérez l’application API minimale suivante.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
app.Run();
public record User(int Id);
Le point de terminaison/users
produit 200 OK
avec une json
représentation de User
quand id
est supérieure à 0
, sinon un code d’état 400 BAD REQUEST
sans corps de réponse. Pour plus d’informations sur la création d’une réponse, consultez Créer des réponses dans les applications API minimales.
Le Status Code Pages middleware
peut être configuré pour produire un contenu de corps commun, lorsqu’il est vide, pour toutes les réponses du client HTTP (499
-400
) ou du serveur (500
-599
). L’intergiciel est configuré en appelant la méthode d’extension UseStatusCodePages .
Par exemple, l’exemple suivant modifie l’application pour répondre avec une charge utile conforme au RFC 7807 au client pour toutes les réponses client et serveur, y compris les erreurs de routage (par exemple, 404 NOT FOUND
). Pour plus d’informations, consultez la section Détails du problème.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStatusCodePages(async statusCodeContext
=> await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
.ExecuteAsync(statusCodeContext.HttpContext));
app.Map("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
app.Run();
public record User(int Id);
Détails du problème
Les détails du problème ne sont pas le seul format de réponse à décrire une erreur d’API HTTP. Toutefois, ils sont couramment utilisés pour signaler des erreurs pour les API HTTP.
Le service des détails du problème implémente l’interface IProblemDetailsService, qui prend en charge la création de détails de problème dans ASP.NET Core. La méthode d’extension AddProblemDetails(IServiceCollection) sur IServiceCollection enregistre l’implémentation IProblemDetailsService
par défaut.
Dans les applications ASP.NET Core, l’intergiciel suivant génère des réponses HTTP sur les détails de problème lorsque AddProblemDetails
est appelé, sauf si l’en-tête HTTP de requêteAccept
n’inclut pas l’un des types de contenu pris en charge par le IProblemDetailsWriter inscrit (par défaut : application/json
) :
- ExceptionHandlerMiddleware : génère une réponse sur les détails du problème lorsqu’un gestionnaire personnalisé n’est pas défini.
- StatusCodePagesMiddleware : génère une réponse de détails de problème par défaut.
- DeveloperExceptionPageMiddleware : génère une réponse sur les détails du problème lors du développement lorsque l’en-tête HTTP de la requête
Accept
n’inclut pastext/html
.
Les applications API minimales peuvent être configurées pour générer une réponse de détails sur le problème pour toutes les réponses d’erreur client et serveur HTTP qui n’ont pas encore de contenu de corps à l’aide de la méthode d’extension AddProblemDetails
.
Le code suivant configure l’application pour générer les détails du problème :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
app.Map("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample Exception"); });
app.Run();
Pour plus d’informations sur l’utilisation de AddProblemDetails
, consultez Détails du problème