Gérer les erreurs dans ASP.NET Core
Par Tom Dykstra
Cet article décrit les approches courantes de gestion des erreurs dans ASP.NET Core applications web. Consultez Gérer les erreurs dans ASP.NET Core API web pour les API web.
Page d’exceptions du développeur
La page d’exception du développeur affiche des informations détaillées sur les exceptions de demande non gérée. ASP.NET Core applications activent la page d’exception du développeur par défaut lorsque les deux :
- Exécution dans l’environnement de développement.
- Application créée avec les modèles actuels, c’est-à-dire à l’aide de WebApplication.CreateBuilder. Les applications créées à l’aide du
WebHost.CreateDefaultBuilder
doivent activer la page d’exception du développeur en appelantapp.UseDeveloperExceptionPage
dansConfigure
.
La page d’exception du développeur s’exécute au début du pipeline d’intergiciels, afin qu’elle puisse intercepter les exceptions non gérées levées dans l’intergiciel (middleware) qui suit.
Les informations détaillées sur les exceptions ne doivent pas être affichées publiquement lorsque l’application s’exécute dans l’environnement de production. Pour plus d’informations sur la configuration des environnements, 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 demande :
- Arborescence des appels de procédure
- Paramètres de chaîne de requête, le cas échéant
- Cookies, le cas échéant
- En-têtes
Il n’est pas garanti que la page d’exception du développeur fournisse des informations. Utilisez journalisation pour obtenir des informations complètes sur l’erreur.
Page Gestionnaire d’exceptions
Pour configurer une page de gestion des erreurs personnalisée pour l’environnement de production, appelez UseExceptionHandler. Cette exception gère l’intergiciel :
- Intercepte et journalise les exceptions non gérées.
- Réexécute la requête dans un autre pipeline à l’aide du chemin indiqué. La demande n’est pas réexécutée si la réponse a démarré. Le code généré par le modèle réexécuta la requête à l’aide du chemin d’accès
/Error
.
Avertissement
Si l’autre pipeline lève une exception qui lui est propre, le middleware de gestion des exceptions repousse l’exception d’origine.
Étant donné que cet intergiciel peut réexécutar le pipeline de requête :
- Les intergiciels doivent gérer la réentrance avec la même requête. Cela signifie normalement nettoyer leur état après l’appel
_next
ou mettre en cache leur traitement sur le pour éviter de leHttpContext
rétablir. Lorsque vous traitez le corps de la demande, cela signifie mettre en mémoire tampon ou mettre en cache les résultats, comme le lecteur de formulaire. - Pour la UseExceptionHandler(IApplicationBuilder, String) surcharge utilisée dans les modèles, seul le chemin de requête est modifié et les données de routage sont effacées. Les données de requête telles que les en-têtes, la méthode et les éléments sont toutes réutilisées telles quelles.
- Les services délimités restent les mêmes.
Dans l’exemple suivant, UseExceptionHandler ajoute l’intergiciel de gestion des exceptions dans les environnements non-développement :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Le Razor modèle d’application Pages fournit une page d’erreur (.cshtml
) et PageModel une classe (ErrorModel
) dans le dossier Pages . Pour une application MVC, le modèle de projet inclut une méthode d’action Error
et une vue Erreur pour le Home contrôleur.
L’intergiciel de gestion des exceptions réexécute la requête à l’aide de la méthode HTTP d’origine . Si un point de terminaison de gestionnaire d’erreurs est limité à un ensemble spécifique de méthodes HTTP, il s’exécute uniquement pour ces méthodes HTTP. Par exemple, une action de contrôleur MVC qui utilise l’attribut [HttpGet]
s’exécute uniquement pour les requêtes GET. Pour vous assurer que toutes les requêtes atteignent la page de gestion des erreurs personnalisée, ne les limitez pas à un ensemble spécifique de méthodes HTTP.
Pour gérer les exceptions différemment en fonction de la méthode HTTP d’origine :
- Pour Razor Pages, créez plusieurs méthodes de gestionnaire. Par exemple, utilisez
OnGet
pour gérer les exceptions GET et utilisezOnPost
pour gérer les exceptions POST. - Pour MVC, appliquez des attributs de verbe HTTP à plusieurs actions. Par exemple, utilisez
[HttpGet]
pour gérer les exceptions GET et utilisez[HttpPost]
pour gérer les exceptions POST.
Pour permettre aux utilisateurs non authentifiés d’afficher la page de gestion des erreurs personnalisée, assurez-vous qu’elle prend en charge l’accès anonyme.
Accéder à l'exception
Utilisez IExceptionHandlerPathFeature pour accéder à l’exception et au chemin de requête d’origine dans un gestionnaire d’erreurs. L’exemple suivant utilise IExceptionHandlerPathFeature
pour obtenir plus d’informations sur l’exception levée :
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
Expression lambda Gestionnaire d’exceptions
En dehors d’une page de gestionnaire d’exceptions personnalisée, il est possible de fournir une expression lambda à UseExceptionHandler, ce qui permet d’accéder à l’erreur avant de retourner la réponse.
Le code suivant utilise un lambda pour la gestion des exceptions :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
UseStatusCodePages
Par défaut, une application ASP.NET Core ne fournit pas de page de codes d’état pour les codes d’état d’erreur HTTP, comme 404 - Introuvable. Lorsque l’application définit un code d’état d’erreur HTTP 400-599 qui n’a pas de corps, elle retourne le code d’état et un corps de réponse vide. Pour activer les gestionnaires de texte uniquement par défaut pour les codes d’état d’erreur courants, appelez UseStatusCodePagesProgram.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Appelez UseStatusCodePages
avant l’intergiciel de gestion des demandes. Par exemple, appelez UseStatusCodePages
avant le middleware de fichier statique et le middleware des points de terminaison.
Quand UseStatusCodePages
n’est pas utilisé, la navigation vers une URL sans point de terminaison renvoie un message d’erreur dépendant du navigateur indiquant que le point de terminaison est introuvable. Quand UseStatusCodePages
est appelé, le navigateur retourne la réponse suivante :
Status Code: 404; Not Found
UseStatusCodePages
n’est généralement pas utilisé en production, car il retourne un message qui n’est pas utile aux utilisateurs.
Notes
Le middleware des pages de codes d’état n’intercepte pas les exceptions. Pour fournir une page de gestion des erreurs personnalisée, utilisez la page du gestionnaire d’exceptions.
UseStatusCodePages avec chaîne de format
Pour personnaliser le texte et le type de contenu de la réponse, utilisez la surcharge de UseStatusCodePages qui prend un type de contenu et une chaîne de format :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Dans le code précédent, {0}
est un espace réservé pour le code d’erreur.
UseStatusCodePages
avec une chaîne de format n’est généralement pas utilisée en production, car elle retourne un message qui n’est pas utile aux utilisateurs.
UseStatusCodePages avec expression lambda
Pour spécifier un code personnalisé de gestion des erreurs et d’écriture de la réponse, utilisez la surcharge de UseStatusCodePages qui prend une expression lambda :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
avec un lambda n’est généralement pas utilisé en production, car il retourne un message qui n’est pas utile aux utilisateurs.
UseStatusCodePagesWithRedirects
La méthode d’extension UseStatusCodePagesWithRedirects :
- Envoie un code d’état 302 - Trouvé au client.
- Redirige le client vers le point de terminaison de gestion des erreurs fourni dans le modèle d’URL. Le point de terminaison de gestion des erreurs affiche généralement des informations d’erreur et retourne HTTP 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Le modèle d’URL peut inclure un {0}
espace réservé pour le code d’état, comme indiqué dans le code précédent. Si le modèle d’URL commence par ~
(tilde), le ~
est remplacé par le modèle d’URL de PathBase
l’application. Lorsque vous spécifiez un point de terminaison dans l’application, créez une vue ou Razor une page MVC pour le point de terminaison.
Cette méthode est généralement utilisée lorsque l’application :
- Doit rediriger le client vers un autre point de terminaison, généralement dans les cas où une autre application traite l’erreur. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison redirigé.
- Ne doit pas conserver ni retourner le code d’état d’origine avec la réponse de redirection initiale.
UseStatusCodePagesWithReExecute
La méthode d’extension UseStatusCodePagesWithReExecute :
- Génère le corps de la réponse en réexécutant le pipeline de requête avec un autre chemin.
- Ne modifie pas le code d’état avant ou après la ré-exécution du pipeline.
La nouvelle exécution du pipeline peut modifier le code d’état de la réponse, car le nouveau pipeline a le contrôle total du code d’état. Si le nouveau pipeline ne modifie pas le code d’état, le code d’état d’origine est envoyé au client.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Si un point de terminaison au sein de l’application est spécifié, créez une vue ou Razor une page MVC pour le point de terminaison.
Cette méthode est généralement utilisée lorsque l’application doit :
- Traiter la demande sans la rediriger vers un autre point de terminaison. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison demandé à l’origine.
- Conserver et retourner le code d’état d’origine avec la réponse.
Le modèle d’URL doit commencer /
par et peut inclure un espace réservé {0}
pour le code d’état. Pour passer le code d’état en tant que paramètre de chaîne de requête, passez un deuxième argument dans UseStatusCodePagesWithReExecute
. Par exemple :
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Le point de terminaison qui traite l’erreur peut récupérer l’URL d’origine qui a généré l’erreur, comme dans l’exemple suivant :
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = string.Join(
statusCodeReExecuteFeature.OriginalPathBase,
statusCodeReExecuteFeature.OriginalPath,
statusCodeReExecuteFeature.OriginalQueryString);
}
}
}
Étant donné que ce middleware peut réexécutar le pipeline de requête :
- Les intergiciels doivent gérer la réentrance avec la même demande. Cela signifie normalement le nettoyage de leur état après l’appel
_next
ou la mise en cache de leur traitement sur leHttpContext
pour éviter de le rétablir. Lorsque vous traitez le corps de la requête, cela signifie soit la mise en mémoire tampon, soit la mise en cache des résultats, comme le lecteur de formulaire. - Les services délimités restent les mêmes.
Désactiver les pages de codes d’état
Pour désactiver les pages de codes d’état d’un contrôleur MVC ou d’une méthode d’action, utilisez l’attribut [SkipStatusCodePages].
Pour désactiver les pages de code d’état pour des demandes spécifiques dans une Razor méthode de gestionnaire Pages ou dans un contrôleur MVC, utilisez IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Code de gestion des exceptions
Le code dans les pages de gestion des exceptions peut également lever des exceptions. Les pages d’erreurs de production doivent être testées de manière approfondie et prendre soin d’éviter de lever leurs propres exceptions.
En-têtes de réponse
Une fois les en-têtes d’une réponse envoyés :
- L’application ne peut pas modifier le code d’état de la réponse.
- Il est impossible d’exécuter les pages d’exception ou les gestionnaires. La réponse doit être accomplie ou la connexion abandonnée.
Gestion des exceptions de serveur
En plus de la logique de gestion des exceptions dans une application, l’implémentation du serveur HTTP peut gérer certaines exceptions. Si le serveur intercepte une exception avant l’envoi des en-têtes de réponse, le serveur envoie une 500 - Internal Server Error
réponse sans corps de réponse. Si le serveur intercepte une exception une fois que les en-têtes de réponse ont été envoyés, il ferme la connexion. Les demandes qui ne sont pas gérées par l’application sont gérées par le serveur. Toute exception qui se produit tandis que le serveur traite la demande est gérée par le dispositif de gestion des exceptions du serveur. Ni les pages d’erreur personnalisées de l’application, ni les intergiciels (middleware) de gestion des exceptions, ni les filtres n’ont d’incidence sur ce comportement.
Gestion des exceptions de démarrage
Seule la couche d’hébergement peut gérer les exceptions qui se produisent au démarrage de l’application. L’hôte peut être configuré pour capturer les erreurs de démarrage et capturer les erreurs détaillées.
La couche d’hébergement ne peut afficher la page d’une erreur de démarrage capturée que si celle-ci se produit une fois la liaison établie entre l’adresse d’hôte et le port. Si la liaison échoue :
- La couche d’hébergement journalise une exception critique.
- Le processus dotnet tombe en panne.
- Aucune page d’erreur n’est affichée lorsque le serveur HTTP est Kestrel.
En cas d’exécution sur IIS (ou Azure App Service) ou IIS Express, une réponse 502.5 - Échec du processus est retournée par le module ASP.NET Core si le processus ne peut pas démarrer. Pour plus d’informations, consultez Résoudre les problèmes d’ASP.NET Core sur Azure App Service et IIS.
Page d’erreur de base de données
Le filtre AddDatabaseDeveloperPageExceptionFilter d’exception de page développeur de base de données capture les exceptions liées à la base de données qui peuvent être résolues à l’aide des migrations Entity Framework Core. Lorsque ces exceptions se produisent, une réponse HTML est générée avec les détails des actions possibles pour résoudre le problème. Cette page est activée uniquement dans l’environnement de développement. Le code suivant ajoute le filtre d’exception de page développeur de base de données :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filtres d’exceptions
Dans les applications MVC, vous pouvez configurer les filtres d’exception globalement, contrôleur par contrôleur ou action par action. Dans Razor les applications Pages, elles peuvent être configurées globalement ou par modèle de page. Ces filtres gèrent toutes les exceptions non gérées qui se produisent pendant l’exécution d’une action de contrôleur ou d’un autre filtre. Pour plus d’informations, consultez Filtres dans ASP.NET Core.
Les filtres d’exception sont utiles pour intercepter les exceptions qui se produisent dans les actions MVC, mais ils ne sont pas aussi flexibles que le middleware de gestion des exceptions intégré, UseExceptionHandler. Nous vous recommandons d’utiliser UseExceptionHandler
, sauf si vous devez effectuer une gestion des erreurs différemment en fonction de l’action MVC choisie.
Erreurs d’état de modèle
Pour plus d’informations sur la gestion des erreurs d’état de modèle, voir Liaison de modèles et Validation de modèles.
Détails du problème
Les détails du problème ne sont pas le seul format de réponse pour décrire une erreur d’API HTTP, mais ils sont couramment utilisés pour signaler des erreurs pour les API HTTP.
Le service détails du problème implémente l’interface, qui prend en charge la IProblemDetailsService création de détails du problème dans ASP.NET Core. La AddProblemDetails
méthode d’extension sur IServiceCollection inscrit l’implémentation par défaut IProblemDetailsService
.
Dans ASP.NET Core applications, l’intergicieliel suivant génère des réponses HTTP de détails de problème lorsque AddProblemDetails
est appelé, sauf lorsque l’en-têteAccept
HTTP de requête n’inclut pas l’un des types de contenu pris en charge par l’inscrit IProblemDetailsWriter (par défaut ) : application/json
- ExceptionHandlerMiddleware: génère une réponse de détails de 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 de détails de problème dans le développement lorsque l’en-tête
Accept
HTTP de requête n’incluttext/html
pas .
Le code suivant configure l’application pour générer une réponse aux détails du problème pour toutes les réponses d’erreur du client et du serveur HTTP qui n’ont pas encore de contenu de corps :
var app = builder.Build();
builder.Services.AddProblemDetails();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
La section suivante montre comment personnaliser le corps de réponse aux détails du problème.
Personnaliser les détails du problème
La création automatique d’un ProblemDetails
peut être personnalisée à l’aide de l’une des options suivantes :
- Utilisez
ProblemDetailsOptions.CustomizeProblemDetails
. - Utiliser un personnalisé
IProblemDetailsWriter
- Appeler dans
IProblemDetailsService
un middleware
Opération CustomizeProblemDetails
Les détails du problème généré peuvent être personnalisés à l’aide CustomizeProblemDetailsde , et les personnalisations sont appliquées à tous les détails du problème générés automatiquement.
Le code suivant utilise ProblemDetailsOptions pour définir CustomizeProblemDetails:
var app = builder.Build();
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Par exemple, un résultat de HTTP Status 400 Bad Request
point de terminaison produit le corps de réponse des détails du problème suivant :
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Personnalisé IProblemDetailsWriter
Une IProblemDetailsWriter implémentation peut être créée pour les personnalisations avancées :
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Détails du problème à partir du middleware
Une autre approche de l’utilisation ProblemDetailsOptions de avec CustomizeProblemDetails consiste à définir l’intergiciel ProblemDetails dans. Une réponse de détails de problème peut être écrite en appelant IProblemDetailsService.WriteAsync
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Dans le code précédent, les points de terminaison /divide
d’API minimaux et /squareroot
retournent la réponse de problème personnalisée attendue lors de l’entrée d’erreur.
Les points de terminaison du contrôleur d’API retournent la réponse au problème par défaut lors de l’entrée d’erreur, et non la réponse de problème personnalisée. La réponse au problème par défaut est retournée, car le contrôleur d’API a écrit dans le flux de réponse, détails du problème pour les codes d’état d’erreur, avant IProblemDetailsService.WriteAsync
d’être appelé et que la réponse n’est plus écrite.
La valeur suivante ValuesController
retourne BadRequestResult, qui écrit dans le flux de réponse et empêche donc le retour de la réponse au problème personnalisé.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Ce qui Values3Controller
suit retourne ControllerBase.Problem
le résultat du problème personnalisé attendu :
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Produire une charge utile ProblemDetails pour les exceptions
Considérez l’application suivante :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Dans les environnements hors développement, lorsqu’une exception se produit, voici une réponse ProblemDetails standard qui est retournée au client :
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Pour la plupart des applications, le code précédent est tout ce qui est nécessaire pour les exceptions. Toutefois, la section suivante montre comment obtenir des réponses plus détaillées aux problèmes.
En dehors d’une page de gestionnaire d’exceptions personnalisée, il est possible de fournir une expression lambda à UseExceptionHandler, L’utilisation d’un lambda permet d’accéder à l’erreur et d’écrire une réponse de détails du problème avec IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Arguement exception";
detail = "Invalid input";
type = "https://errors.example.com/arguementException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
Une autre approche pour générer les détails du problème consiste à utiliser le package NuGet tiers Hellang.Middleware.ProblemDetails qui peut être utilisé pour mapper des exceptions et des erreurs client aux détails du problème.
Ressources supplémentaires
Par Tom Dykstra
Cet article décrit les approches courantes de gestion des erreurs dans ASP.NET Core applications web. Consultez Gérer les erreurs dans ASP.NET Core API web pour les API web.
Page d’exceptions du développeur
La page d’exception du développeur affiche des informations détaillées sur les exceptions de demande non gérée. ASP.NET Core applications activent la page d’exception du développeur par défaut lorsque les deux :
- Exécution dans l’environnement de développement.
- Application créée avec les modèles actuels, c’est-à-dire à l’aide de WebApplication.CreateBuilder. Les applications créées à l’aide du
WebHost.CreateDefaultBuilder
doivent activer la page d’exception du développeur en appelantapp.UseDeveloperExceptionPage
dansConfigure
.
La page d’exception du développeur s’exécute au début du pipeline d’intergiciels, afin qu’elle puisse intercepter les exceptions non gérées levées dans l’intergiciel (middleware) qui suit.
Les informations détaillées sur les exceptions ne doivent pas être affichées publiquement lorsque l’application s’exécute dans l’environnement de production. Pour plus d’informations sur la configuration des environnements, 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 demande :
- Arborescence des appels de procédure
- Paramètres de chaîne de requête, le cas échéant
- Cookies, le cas échéant
- En-têtes
Il n’est pas garanti que la page d’exception du développeur fournisse des informations. Utilisez journalisation pour obtenir des informations complètes sur l’erreur.
Page Gestionnaire d’exceptions
Pour configurer une page de gestion des erreurs personnalisée pour l’environnement de production, appelez UseExceptionHandler. Cette exception gère l’intergiciel :
- Intercepte et journalise les exceptions non gérées.
- Réexécute la requête dans un autre pipeline à l’aide du chemin indiqué. La demande n’est pas réexécutée si la réponse a démarré. Le code généré par le modèle réexécuta la requête à l’aide du chemin d’accès
/Error
.
Avertissement
Si l’autre pipeline lève une exception qui lui est propre, le middleware de gestion des exceptions repousse l’exception d’origine.
Dans l’exemple suivant, UseExceptionHandler ajoute l’intergiciel de gestion des exceptions dans les environnements non-développement :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Le Razor modèle d’application Pages fournit une page d’erreur (.cshtml
) et PageModel une classe (ErrorModel
) dans le dossier Pages . Pour une application MVC, le modèle de projet inclut une méthode d’action Error
et une vue Erreur pour le Home contrôleur.
L’intergiciel de gestion des exceptions réexécute la requête à l’aide de la méthode HTTP d’origine . Si un point de terminaison de gestionnaire d’erreurs est limité à un ensemble spécifique de méthodes HTTP, il s’exécute uniquement pour ces méthodes HTTP. Par exemple, une action de contrôleur MVC qui utilise l’attribut [HttpGet]
s’exécute uniquement pour les requêtes GET. Pour vous assurer que toutes les requêtes atteignent la page de gestion des erreurs personnalisée, ne les limitez pas à un ensemble spécifique de méthodes HTTP.
Pour gérer les exceptions différemment en fonction de la méthode HTTP d’origine :
- Pour Razor Pages, créez plusieurs méthodes de gestionnaire. Par exemple, utilisez
OnGet
pour gérer les exceptions GET et utilisezOnPost
pour gérer les exceptions POST. - Pour MVC, appliquez des attributs de verbe HTTP à plusieurs actions. Par exemple, utilisez
[HttpGet]
pour gérer les exceptions GET et utilisez[HttpPost]
pour gérer les exceptions POST.
Pour permettre aux utilisateurs non authentifiés d’afficher la page de gestion des erreurs personnalisée, assurez-vous qu’elle prend en charge l’accès anonyme.
Accéder à l'exception
Utilisez IExceptionHandlerPathFeature pour accéder à l’exception et au chemin de requête d’origine dans un gestionnaire d’erreurs. L’exemple suivant utilise IExceptionHandlerPathFeature
pour obtenir plus d’informations sur l’exception levée :
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
Expression lambda Gestionnaire d’exceptions
En dehors d’une page de gestionnaire d’exceptions personnalisée, il est possible de fournir une expression lambda à UseExceptionHandler, ce qui permet d’accéder à l’erreur avant de retourner la réponse.
Le code suivant utilise un lambda pour la gestion des exceptions :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
UseStatusCodePages
Par défaut, une application ASP.NET Core ne fournit pas de page de codes d’état pour les codes d’état d’erreur HTTP, comme 404 - Introuvable. Lorsque l’application définit un code d’état d’erreur HTTP 400-599 qui n’a pas de corps, elle retourne le code d’état et un corps de réponse vide. Pour activer les gestionnaires de texte uniquement par défaut pour les codes d’état d’erreur courants, appelez UseStatusCodePagesProgram.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Appelez UseStatusCodePages
avant l’intergiciel de gestion des demandes. Par exemple, appelez UseStatusCodePages
avant le middleware de fichier statique et le middleware des points de terminaison.
Quand UseStatusCodePages
n’est pas utilisé, la navigation vers une URL sans point de terminaison renvoie un message d’erreur dépendant du navigateur indiquant que le point de terminaison est introuvable. Quand UseStatusCodePages
est appelé, le navigateur retourne la réponse suivante :
Status Code: 404; Not Found
UseStatusCodePages
n’est généralement pas utilisé en production, car il retourne un message qui n’est pas utile aux utilisateurs.
Notes
Le middleware des pages de codes d’état n’intercepte pas les exceptions. Pour fournir une page de gestion des erreurs personnalisée, utilisez la page du gestionnaire d’exceptions.
UseStatusCodePages avec chaîne de format
Pour personnaliser le texte et le type de contenu de la réponse, utilisez la surcharge de UseStatusCodePages qui prend un type de contenu et une chaîne de format :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Dans le code précédent, {0}
est un espace réservé pour le code d’erreur.
UseStatusCodePages
avec une chaîne de format n’est généralement pas utilisée en production, car elle retourne un message qui n’est pas utile aux utilisateurs.
UseStatusCodePages avec expression lambda
Pour spécifier un code personnalisé de gestion des erreurs et d’écriture de la réponse, utilisez la surcharge de UseStatusCodePages qui prend une expression lambda :
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
avec un lambda n’est généralement pas utilisé en production, car il retourne un message qui n’est pas utile aux utilisateurs.
UseStatusCodePagesWithRedirects
La méthode d’extension UseStatusCodePagesWithRedirects :
- Envoie un code d’état 302 - Trouvé au client.
- Redirige le client vers le point de terminaison de gestion des erreurs fourni dans le modèle d’URL. Le point de terminaison de gestion des erreurs affiche généralement des informations d’erreur et retourne HTTP 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Le modèle d’URL peut inclure un {0}
espace réservé pour le code d’état, comme indiqué dans le code précédent. Si le modèle d’URL commence par ~
(tilde), le ~
est remplacé par le modèle d’URL de PathBase
l’application. Lorsque vous spécifiez un point de terminaison dans l’application, créez une vue ou Razor une page MVC pour le point de terminaison.
Cette méthode est généralement utilisée lorsque l’application :
- Doit rediriger le client vers un autre point de terminaison, généralement dans les cas où une autre application traite l’erreur. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison redirigé.
- Ne doit pas conserver ni retourner le code d’état d’origine avec la réponse de redirection initiale.
UseStatusCodePagesWithReExecute
La méthode d’extension UseStatusCodePagesWithReExecute :
- Retourne le code d’état d’origine au client.
- Génère le corps de la réponse en réexécutant le pipeline de requête avec un autre chemin.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Si un point de terminaison dans l’application est spécifié, créez une vue ou Razor une page MVC pour le point de terminaison.
Cette méthode est généralement utilisée lorsque l’application doit :
- Traiter la demande sans la rediriger vers un autre point de terminaison. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison demandé à l’origine.
- Conserver et retourner le code d’état d’origine avec la réponse.
Le modèle d’URL doit commencer par /
et peut inclure un espace réservé {0}
pour le code d’état. Pour passer le code d’état en tant que paramètre de chaîne de requête, passez un deuxième argument dans UseStatusCodePagesWithReExecute
. Par exemple :
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Le point de terminaison qui traite l’erreur peut récupérer l’URL d’origine qui a généré l’erreur, comme dans l’exemple suivant :
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = string.Join(
statusCodeReExecuteFeature.OriginalPathBase,
statusCodeReExecuteFeature.OriginalPath,
statusCodeReExecuteFeature.OriginalQueryString);
}
}
}
Désactiver les pages de codes d’état
Pour désactiver les pages de codes d’état d’un contrôleur MVC ou d’une méthode d’action, utilisez l’attribut [SkipStatusCodePages].
Pour désactiver les pages de code d’état pour des demandes spécifiques dans une Razor méthode de gestionnaire Pages ou dans un contrôleur MVC, utilisez IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Code de gestion des exceptions
Le code dans les pages de gestion des exceptions peut également lever des exceptions. Les pages d’erreurs de production doivent être testées de manière approfondie et prendre soin d’éviter de lever leurs propres exceptions.
En-têtes de réponse
Une fois les en-têtes d’une réponse envoyés :
- L’application ne peut pas modifier le code d’état de la réponse.
- Il est impossible d’exécuter les pages d’exception ou les gestionnaires. La réponse doit être accomplie ou la connexion abandonnée.
Gestion des exceptions de serveur
En plus de la logique de gestion des exceptions dans une application, l’implémentation du serveur HTTP peut gérer certaines exceptions. Si le serveur intercepte une exception avant l’envoi des en-têtes de réponse, le serveur envoie une 500 - Internal Server Error
réponse sans corps de réponse. Si le serveur intercepte une exception une fois que les en-têtes de réponse ont été envoyés, il ferme la connexion. Les demandes qui ne sont pas gérées par l’application sont gérées par le serveur. Toute exception qui se produit tandis que le serveur traite la demande est gérée par le dispositif de gestion des exceptions du serveur. Ni les pages d’erreur personnalisées de l’application, ni les intergiciels (middleware) de gestion des exceptions, ni les filtres n’ont d’incidence sur ce comportement.
Gestion des exceptions de démarrage
Seule la couche d’hébergement peut gérer les exceptions qui se produisent au démarrage de l’application. L’hôte peut être configuré pour capturer les erreurs de démarrage et capturer les erreurs détaillées.
La couche d’hébergement ne peut afficher la page d’une erreur de démarrage capturée que si celle-ci se produit une fois la liaison établie entre l’adresse d’hôte et le port. Si la liaison échoue :
- La couche d’hébergement journalise une exception critique.
- Le processus dotnet tombe en panne.
- Aucune page d’erreur n’est affichée lorsque le serveur HTTP est Kestrel.
En cas d’exécution sur IIS (ou Azure App Service) ou IIS Express, une réponse 502.5 - Échec du processus est retournée par le module ASP.NET Core si le processus ne peut pas démarrer. Pour plus d’informations, consultez Résoudre les problèmes d’ASP.NET Core sur Azure App Service et IIS.
Page d’erreur de base de données
Le filtre AddDatabaseDeveloperPageExceptionFilter d’exception de page développeur de base de données capture les exceptions liées à la base de données qui peuvent être résolues à l’aide des migrations Entity Framework Core. Lorsque ces exceptions se produisent, une réponse HTML est générée avec les détails des actions possibles pour résoudre le problème. Cette page est activée uniquement dans l’environnement de développement. Le code suivant ajoute le filtre d’exception de page développeur de base de données :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filtres d’exceptions
Dans les applications MVC, vous pouvez configurer les filtres d’exception globalement, contrôleur par contrôleur ou action par action. Dans Razor les applications Pages, elles peuvent être configurées globalement ou par modèle de page. Ces filtres gèrent toutes les exceptions non gérées qui se produisent pendant l’exécution d’une action de contrôleur ou d’un autre filtre. Pour plus d’informations, consultez Filtres dans ASP.NET Core.
Les filtres d’exception sont utiles pour intercepter les exceptions qui se produisent dans les actions MVC, mais ils ne sont pas aussi flexibles que le middleware de gestion des exceptions intégré, UseExceptionHandler. Nous vous recommandons d’utiliser UseExceptionHandler
, sauf si vous devez effectuer une gestion des erreurs différemment en fonction de l’action MVC choisie.
Erreurs d’état de modèle
Pour plus d’informations sur la gestion des erreurs d’état de modèle, voir Liaison de modèles et Validation de modèles.
Ressources supplémentaires
Par Kirk Larkin, Tom Dykstra et Steve Smith
Cet article décrit les approches courantes de gestion des erreurs dans ASP.NET Core applications web. Consultez Gérer les erreurs dans ASP.NET Core API web pour les API web.
Affichez ou téléchargez l’exemple de code. (Guide pratique pour télécharger.) L’onglet réseau des outils de développement du navigateur F12 est utile lors du test de l’exemple d’application.
Page d’exceptions du développeur
La page Exception du développeur affiche des informations détaillées sur les exceptions de requête non prises en charge. Les modèles ASP.NET Core génèrent le code suivant :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Le code en surbrillance précédent active la page d’exception du développeur lorsque l’application s’exécute dans l’environnement de développement.
Les modèles se placent UseDeveloperExceptionPage tôt dans le pipeline middleware afin qu’il puisse intercepter les exceptions non prises en charge levées dans le middleware qui suit.
Le code précédent active la page d’exception du développeur uniquement lorsque l’application s’exécute dans l’environnement de développement. Les informations détaillées sur les exceptions ne doivent pas être affichées publiquement lorsque l’application s’exécute dans l’environnement de production. Pour plus d’informations sur la configuration des environnements, consultez Utiliser plusieurs environnements dans ASP.NET Core.
La page Exception du développeur peut inclure les informations suivantes sur l’exception et la demande :
- Arborescence des appels de procédure
- Paramètres de chaîne de requête le cas échéant
- Cookies le cas échéant
- En-têtes
La page d’exception du développeur n’est pas garantie de fournir des informations. Utilisez journalisation pour obtenir des informations d’erreur complètes.
Page Gestionnaire d’exceptions
Pour configurer une page de gestion des erreurs personnalisée pour l’environnement de production, appelez UseExceptionHandler. Cette exception de gestion des intergiciels :
- Intercepte et consigne les exceptions non gérées.
- Réexécute la demande dans un autre pipeline à l’aide du chemin indiqué. La demande n’est pas réexécutée si la réponse a démarré. Le code généré par le modèle réexécute la demande à l’aide du chemin d’accès
/Error
.
Avertissement
Si le pipeline de remplacement lève une exception de son propre, la gestion des intergiciels d’exception relance l’exception d’origine.
Dans l’exemple suivant, UseExceptionHandler ajoute l’intergiciel de gestion des exceptions dans les environnements non-développement :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Le Razor modèle d’application Pages fournit une page d’erreur (.cshtml
) et PageModel une classe (ErrorModel
) dans le dossier Pages . Pour une application MVC, le modèle de projet inclut une méthode d’action Error
et une vue d’erreur pour le Home contrôleur.
L’intergicieliel de gestion des exceptions réexécute la demande à l’aide de la méthode HTTP d’origine . Si un point de terminaison de gestionnaire d’erreurs est limité à un ensemble spécifique de méthodes HTTP, il s’exécute uniquement pour ces méthodes HTTP. Par exemple, une action de contrôleur MVC qui utilise l’attribut s’exécute uniquement pour les [HttpGet]
requêtes GET. Pour vous assurer que toutes les requêtes atteignent la page de gestion des erreurs personnalisées, ne les limitez pas à un ensemble spécifique de méthodes HTTP.
Pour gérer les exceptions différemment en fonction de la méthode HTTP d’origine :
- Pour Razor Pages, créez plusieurs méthodes de gestionnaire. Par exemple, utilisez
OnGet
pour gérer les exceptions GET et utilisezOnPost
pour gérer les exceptions POST. - Pour MVC, appliquez des attributs de verbe HTTP à plusieurs actions. Par exemple, utilisez
[HttpGet]
pour gérer les exceptions GET et utilisez[HttpPost]
pour gérer les exceptions POST.
Pour permettre aux utilisateurs non authentifiés d’afficher la page de gestion des erreurs personnalisée, assurez-vous qu’elle prend en charge l’accès anonyme.
Accéder à l'exception
Utilisez IExceptionHandlerPathFeature pour accéder à l’exception et au chemin de requête d’origine dans un gestionnaire d’erreurs. Le code suivant ajoute ExceptionMessage
à la valeur par défaut Pages/Error.cshtml.cs
générée par les modèles ASP.NET Core :
[ResponseCache(Duration=0, Location=ResponseCacheLocation.None, NoStore=true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ExceptionMessage { get; set; }
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
_logger.LogError(ExceptionMessage);
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
Pour tester l’exception dans l’exemple d’application :
- Définissez l’environnement sur production.
- Supprimez les commentaires de
webBuilder.UseStartup<Startup>();
dansProgram.cs
. - Sélectionnez Déclencher une exception sur la page d’accueil.
Expression lambda Gestionnaire d’exceptions
En dehors d’une page de gestionnaire d’exceptions personnalisée, il est possible de fournir une expression lambda à UseExceptionHandler, ce qui permet d’accéder à l’erreur avant de retourner la réponse.
Le code suivant utilise un lambda pour la gestion des exceptions :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(
"File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync(
"<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512));
});
});
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Avertissement
Ne distribuez pas d’informations sensibles sur les erreurs de IExceptionHandlerFeature ou de IExceptionHandlerPathFeature aux clients. Cela représenterait un risque de sécurité.
Pour tester la gestion des exceptions lambda dans l’exemple d’application :
- Définissez l’environnement sur production.
- Supprimez les commentaires de
webBuilder.UseStartup<StartupLambda>();
dansProgram.cs
. - Sélectionnez Déclencher une exception sur la page d’accueil.
UseStatusCodePages
Par défaut, une application ASP.NET Core ne fournit pas de page de code d’état pour les codes d’état d’erreur HTTP, tels que 404 - Introuvable. Lorsque l’application définit un code d’état d’erreur HTTP 400-599 qui n’a pas de corps, elle retourne le code d’état et un corps de réponse vide. Pour fournir des pages de code d’état, utilisez le middleware pages de code d’état. Pour activer les gestionnaires exclusivement textuels par défaut des codes d’état d’erreur courants, appelez UseStatusCodePages dans la méthode Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Appelez UseStatusCodePages
avant la demande de gestion du middleware. Par exemple, appelez UseStatusCodePages
avant le middleware de fichier statique et le middleware des points de terminaison.
Quand UseStatusCodePages
n’est pas utilisé, la navigation vers une URL sans point de terminaison renvoie un message d’erreur dépendant du navigateur indiquant que le point de terminaison est introuvable. Par exemple, accédez à Home/Privacy2
. Quand UseStatusCodePages
est appelé, le navigateur retourne :
Status Code: 404; Not Found
UseStatusCodePages
n’est généralement pas utilisé en production, car il retourne un message qui n’est pas utile aux utilisateurs.
Pour tester UseStatusCodePages
dans l’exemple d’application :
- Définissez l’environnement sur production.
- Supprimez les commentaires de
webBuilder.UseStartup<StartupUseStatusCodePages>();
dansProgram.cs
. - Sélectionnez les liens sur la page d’accueil de la page d’accueil.
Notes
Le middleware des pages de code d’état n’intercepte pas d’exceptions. Pour fournir une page de gestion des erreurs personnalisée, utilisez la page du gestionnaire d’exceptions.
UseStatusCodePages avec chaîne de format
Pour personnaliser le texte et le type de contenu de la réponse, utilisez la surcharge de UseStatusCodePages qui prend un type de contenu et une chaîne de format :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Dans le code précédent, {0}
est un espace réservé pour le code d’erreur.
UseStatusCodePages
avec une chaîne de format n’est généralement pas utilisée en production, car elle retourne un message qui n’est pas utile pour les utilisateurs.
Pour tester UseStatusCodePages
dans l’exemple d’application, supprimez les commentaires de webBuilder.UseStartup<StartupFormat>();
dans Program.cs
.
UseStatusCodePages avec expression lambda
Pour spécifier un code personnalisé de gestion des erreurs et d’écriture de la réponse, utilisez la surcharge de UseStatusCodePages qui prend une expression lambda :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
UseStatusCodePages
avec un lambda n’est généralement pas utilisé en production, car il retourne un message qui n’est pas utile pour les utilisateurs.
Pour tester UseStatusCodePages
dans l’exemple d’application, supprimez les commentaires de webBuilder.UseStartup<StartupStatusLambda>();
dans Program.cs
.
UseStatusCodePagesWithRedirects
La méthode d’extension UseStatusCodePagesWithRedirects :
- Envoie un code d’état 302 - Trouvé au client.
- Redirige le client vers le point de terminaison de gestion des erreurs fourni dans le modèle d’URL. Le point de terminaison de gestion des erreurs affiche généralement les informations d’erreur et retourne HTTP 200.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/MyStatusCode?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Le modèle d’URL peut inclure un {0}
espace réservé pour le code d’état, comme indiqué dans le code précédent. Si le modèle d’URL commence par ~
(tilde), le ~
est remplacé par l’application PathBase
. Lorsque vous spécifiez un point de terminaison dans l’application, créez une vue ou Razor une page MVC pour le point de terminaison. Pour obtenir un Razor exemple pages, consultez Pages/MyStatusCode.cshtml dans l’exemple d’application.
Cette méthode est généralement utilisée lorsque l’application :
- Doit rediriger le client vers un autre point de terminaison, généralement dans les cas où une autre application traite l’erreur. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison redirigé.
- Ne doit pas conserver ni retourner le code d’état d’origine avec la réponse de redirection initiale.
Pour tester UseStatusCodePages
dans l’exemple d’application, supprimez les commentaires de webBuilder.UseStartup<StartupSCredirect>();
dans Program.cs
.
UseStatusCodePagesWithReExecute
La méthode d’extension UseStatusCodePagesWithReExecute :
- Retourne le code d’état d’origine au client.
- Génère le corps de la réponse en réexécutant le pipeline de requête avec un autre chemin.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/MyStatusCode2", "?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Si un point de terminaison au sein de l’application est spécifié, créez une vue ou Razor une page MVC pour le point de terminaison. Assurez-vous que UseStatusCodePagesWithReExecute
est placé avant UseRouting
que la demande puisse être redirigée vers la page d’état. Pour obtenir un Razor exemple pages, consultez Pages/MyStatusCode2.cshtml dans l’exemple d’application.
Cette méthode est généralement utilisée lorsque l’application doit :
- Traiter la demande sans la rediriger vers un autre point de terminaison. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison demandé à l’origine.
- Conserver et retourner le code d’état d’origine avec la réponse.
Les modèles d’URL et de chaîne de requête peuvent inclure un espace réservé {0}
pour le code d’état. Le modèle d’URL doit commencer /
par .
Le point de terminaison qui traite l’erreur peut récupérer l’URL d’origine qui a généré l’erreur, comme dans l’exemple suivant :
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class MyStatusCode2Model : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ErrorStatusCode { get; set; }
public string OriginalURL { get; set; }
public bool ShowOriginalURL => !string.IsNullOrEmpty(OriginalURL);
public void OnGet(string code)
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
ErrorStatusCode = code;
var statusCodeReExecuteFeature = HttpContext.Features.Get<
IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
}
}
Pour obtenir un Razor exemple pages, consultez Pages/MyStatusCode2.cshtml dans l’exemple d’application.
Pour tester UseStatusCodePages
dans l’exemple d’application, supprimez les commentaires de webBuilder.UseStartup<StartupSCreX>();
dans Program.cs
.
Désactiver les pages de codes d’état
Pour désactiver les pages de codes d’état d’un contrôleur MVC ou d’une méthode d’action, utilisez l’attribut [SkipStatusCodePages].
Pour désactiver les pages de code d’état pour des demandes spécifiques dans une Razor méthode de gestionnaire Pages ou dans un contrôleur MVC, utilisez IStatusCodePagesFeature:
public void OnGet()
{
// using Microsoft.AspNetCore.Diagnostics;
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
}
Code de gestion des exceptions
Le code dans les pages de gestion des exceptions peut également lever des exceptions. Les pages d’erreurs de production doivent être testées de manière approfondie et prendre soin d’éviter de lever leurs propres exceptions.
En-têtes de réponse
Une fois les en-têtes d’une réponse envoyés :
- L’application ne peut pas modifier le code d’état de la réponse.
- Il est impossible d’exécuter les pages d’exception ou les gestionnaires. La réponse doit être accomplie ou la connexion abandonnée.
Gestion des exceptions de serveur
En plus de la logique de gestion des exceptions dans une application, l’implémentation du serveur HTTP peut gérer certaines exceptions. Si le serveur intercepte une exception avant l’envoi des en-têtes de réponse, le serveur envoie une 500 - Internal Server Error
réponse sans corps de réponse. Si le serveur intercepte une exception une fois que les en-têtes de réponse ont été envoyés, il ferme la connexion. Les demandes qui ne sont pas gérées par l’application sont gérées par le serveur. Toute exception qui se produit tandis que le serveur traite la demande est gérée par le dispositif de gestion des exceptions du serveur. Ni les pages d’erreur personnalisées de l’application, ni les intergiciels (middleware) de gestion des exceptions, ni les filtres n’ont d’incidence sur ce comportement.
Gestion des exceptions de démarrage
Seule la couche d’hébergement peut gérer les exceptions qui se produisent au démarrage de l’application. L’hôte peut être configuré pour capturer les erreurs de démarrage et capturer les erreurs détaillées.
La couche d’hébergement ne peut afficher la page d’une erreur de démarrage capturée que si celle-ci se produit une fois la liaison établie entre l’adresse d’hôte et le port. Si la liaison échoue :
- La couche d’hébergement journalise une exception critique.
- Le processus dotnet tombe en panne.
- Aucune page d’erreur n’est affichée lorsque le serveur HTTP est Kestrel.
En cas d’exécution sur IIS (ou Azure App Service) ou IIS Express, une réponse 502.5 - Échec du processus est retournée par le module ASP.NET Core si le processus ne peut pas démarrer. Pour plus d’informations, consultez Résoudre les problèmes d’ASP.NET Core sur Azure App Service et IIS.
Page d’erreur de base de données
Le filtre AddDatabaseDeveloperPageExceptionFilter
d’exception de page développeur de base de données capture les exceptions liées à la base de données qui peuvent être résolues à l’aide des migrations Entity Framework Core. Lorsque ces exceptions se produisent, une réponse HTML est générée avec les détails des actions possibles pour résoudre le problème. Cette page est activée uniquement dans l’environnement de développement. Le code suivant a été généré par les modèles ASP.NET Core Razor Pages lorsque des comptes d’utilisateur individuels ont été spécifiés :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
}
Filtres d’exceptions
Dans les applications MVC, vous pouvez configurer les filtres d’exception globalement, contrôleur par contrôleur ou action par action. Dans Razor les applications Pages, elles peuvent être configurées globalement ou par modèle de page. Ces filtres gèrent toutes les exceptions non gérées qui se produisent pendant l’exécution d’une action de contrôleur ou d’un autre filtre. Pour plus d’informations, consultez Filtres dans ASP.NET Core.
Les filtres d’exception sont utiles pour intercepter les exceptions qui se produisent dans les actions MVC, mais ils ne sont pas aussi flexibles que le middleware de gestion des exceptions intégré, UseExceptionHandler
. Nous vous recommandons d’utiliser UseExceptionHandler
, sauf si vous devez effectuer une gestion des erreurs différemment en fonction de l’action MVC choisie.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Erreurs d’état de modèle
Pour plus d’informations sur la gestion des erreurs d’état de modèle, voir Liaison de modèles et Validation de modèles.
Ressources supplémentaires
Par Tom Dykstra, et Steve Smith
Cet article décrit les approches courantes de gestion des erreurs dans ASP.NET Core applications web. Consultez Gérer les erreurs dans ASP.NET Core API web pour les API web.
Affichez ou téléchargez l’exemple de code. (Guide pratique pour télécharger.)
Page d’exceptions du développeur
La Page d’exceptions du développeur affiche des informations détaillées sur les exceptions des demandes. Les modèles ASP.NET Core génèrent le code suivant :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Le code précédent active la page d’exception du développeur lorsque l’application s’exécute dans l’environnement de développement.
Les modèles se placent UseDeveloperExceptionPage avant tout intergiciel afin que les exceptions soient interceptées dans le middleware qui suit.
Le code précédent active la page d’exception du développeur uniquement lorsque l’application s’exécute dans l’environnement de développement. Les informations détaillées sur les exceptions ne doivent pas être affichées publiquement lorsque l’application s’exécute en production. Pour plus d’informations sur la configuration des environnements, consultez Utiliser plusieurs environnements dans ASP.NET Core.
La page Exception du développeur contient les informations suivantes sur l’exception et la demande :
- Arborescence des appels de procédure
- Paramètres de chaîne de requête le cas échéant
- Cookies le cas échéant
- En-têtes
Page Gestionnaire d’exceptions
Pour configurer une page de gestion des erreurs personnalisée en fonction de l’environnement de production, utilisez le middleware de gestion des exceptions. Le middleware :
- Intercepte et consigne les exceptions.
- Réexécute la requête dans un autre pipeline pour la page ou le contrôleur indiqué(e). La demande n’est pas réexécutée si la réponse a démarré. Le code généré par le modèle réexécute la demande à
/Error
.
Dans l’exemple suivant, UseExceptionHandler ajoute le middleware de gestion des exceptions dans des environnements autres que les environnements de développement :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Le Razor modèle d’application Pages fournit une page d’erreur (.cshtml
) et PageModel une classe (ErrorModel
) dans le dossier Pages . Pour une application MVC, le modèle de projet inclut une méthode d’action Error et une vue Erreur dans le Home contrôleur.
Ne marquez pas la méthode d’action du gestionnaire d’erreurs avec des attributs de méthode HTTP, tels que HttpGet
. Les verbes explicites empêchent certaines demandes d’atteindre la méthode. Autorisez l’accès anonyme à la méthode si les utilisateurs non authentifiés doivent voir la vue d’erreur.
Accéder à l'exception
Utilisez IExceptionHandlerPathFeature pour accéder à l’exception et au chemin de la demande d’origine dans une page ou un contrôleur de gestionnaire d’erreurs :
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
Avertissement
Ne communiquez pas d’informations sensibles sur les erreurs aux clients. Cela représenterait un risque de sécurité.
Pour déclencher la page de gestion des exceptions précédente, définissez l’environnement sur productions et forcez une exception.
Expression lambda Gestionnaire d’exceptions
En dehors d’une page de gestionnaire d’exceptions personnalisée, il est possible de fournir une expression lambda à UseExceptionHandler, ce qui permet d’accéder à l’erreur avant de retourner la réponse.
Voici un exemple d’utilisation d’une expression lambda pour la gestion des exceptions :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512)); // IE padding
});
});
app.UseHsts();
}
Dans le code précédent, est ajouté afin await context.Response.WriteAsync(new string(' ', 512));
que le navigateur Internet Explorer affiche le message d’erreur plutôt qu’un message d’erreur IE. Pour plus d’informations, consultez ce problème GitHub.
Avertissement
Ne distribuez pas d’informations sensibles sur les erreurs de IExceptionHandlerFeature ou de IExceptionHandlerPathFeature aux clients. Cela représenterait un risque de sécurité.
Pour afficher le résultat de l’expression lambda de gestion des exceptions dans l’exemple d’application, utilisez les directive de préprocesseur ProdEnvironment
et ErrorHandlerLambda
et sélectionnez Déclencher une exception sur la page d’accueil.
UseStatusCodePages
Par défaut, une application ASP.NET Core ne fournit pas une page de codes d’état pour les codes d’état HTTP, comme 404 - Introuvable. L’application retourne un code d’état et un corps de réponse vide. Pour fournir des pages de codes d’état, utilisez le middleware Pages de codes d’état.
L’intergiciel est mis à disposition par le package Microsoft.AspNetCore.Diagnostics .
Pour activer les gestionnaires exclusivement textuels par défaut des codes d’état d’erreur courants, appelez UseStatusCodePages dans la méthode Startup.Configure
:
app.UseStatusCodePages();
Appelez UseStatusCodePages
avant les middlewares de gestion des demandes (par exemple, le middleware de fichiers statiques et le middleware MVC).
Quand UseStatusCodePages
n’est pas utilisé, la navigation vers une URL sans point de terminaison renvoie un message d’erreur dépendant du navigateur indiquant que le point de terminaison est introuvable. Par exemple, accédez à Home/Privacy2
. Quand UseStatusCodePages
est appelé, le navigateur retourne :
Status Code: 404; Not Found
UseStatusCodePages avec chaîne de format
Pour personnaliser le texte et le type de contenu de la réponse, utilisez la surcharge de UseStatusCodePages qui prend un type de contenu et une chaîne de format :
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
UseStatusCodePages avec expression lambda
Pour spécifier un code personnalisé de gestion des erreurs et d’écriture de la réponse, utilisez la surcharge de UseStatusCodePages qui prend une expression lambda :
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
UseStatusCodePagesWithRedirects
La méthode d’extension UseStatusCodePagesWithRedirects :
- Envoie un code d’état 302 - Trouvé au client.
- Redirige le client à l’emplacement fourni dans le modèle d’URL.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");
Le modèle d’URL peut comporter un espace réservé {0}
pour le code d’état, comme dans l’exemple. Si le modèle d’URL commence par ~
(tilde), le ~
est remplacé par l’application PathBase
. Si vous pointez vers un point de terminaison dans l’application, créez une vue ou Razor une page MVC pour le point de terminaison. Pour obtenir un Razor exemple pages, consultez Pages/StatusCode.cshtml
dans l’exemple d’application.
Cette méthode est généralement utilisée lorsque l’application :
- Doit rediriger le client vers un autre point de terminaison, généralement dans les cas où une autre application traite l’erreur. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison redirigé.
- Ne doit pas conserver ni retourner le code d’état d’origine avec la réponse de redirection initiale.
UseStatusCodePagesWithReExecute
La méthode d’extension UseStatusCodePagesWithReExecute :
- Retourne le code d’état d’origine au client.
- Génère le corps de la réponse en réexécutant le pipeline de requête avec un autre chemin.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
Si vous pointez vers un point de terminaison dans l’application, créez une vue ou Razor une page MVC pour le point de terminaison. Assurez-vous que UseStatusCodePagesWithReExecute
est placé avant UseRouting
que la demande puisse être redirigée vers la page d’état. Pour obtenir un Razor exemple pages, consultez Pages/StatusCode.cshtml
dans l’exemple d’application.
Cette méthode est généralement utilisée lorsque l’application doit :
- Traiter la demande sans la rediriger vers un autre point de terminaison. Pour les applications web, la barre d’adresses du navigateur client reflète le point de terminaison demandé à l’origine.
- Conserver et retourner le code d’état d’origine avec la réponse.
Les modèles d’URL et de chaîne de requête peuvent comporter un espace réservé ({0}
) pour le code d’état. Le modèle d’URL doit commencer par une barre oblique (/
). Si vous utilisez un espace réservé dans le chemin, vérifiez que le point de terminaison (page ou contrôleur) peut traiter le segment de chemin. Par exemple, une Razor page pour les erreurs doit accepter la valeur de segment de chemin d’accès facultative avec la @page
directive :
@page "{code?}"
Le point de terminaison qui traite l’erreur peut récupérer l’URL d’origine qui a généré l’erreur, comme dans l’exemple suivant :
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Ne marquez pas la méthode d’action du gestionnaire d’erreurs avec des attributs de méthode HTTP, tels que HttpGet
. Les verbes explicites empêchent certaines demandes d’atteindre la méthode. Autorisez l’accès anonyme à la méthode si les utilisateurs non authentifiés doivent voir la vue d’erreur.
Désactiver les pages de codes d’état
Pour désactiver les pages de code d’état pour un contrôleur MVC ou une méthode d’action, utilisez l’attribut [SkipStatusCodePages]
.
Pour désactiver les pages de code d’état pour des demandes spécifiques dans une Razor méthode de gestionnaire Pages ou dans un contrôleur MVC, utilisez IStatusCodePagesFeature:
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
Code de gestion des exceptions
Le code dans les pages de gestion des exceptions peut lever des exceptions. Il est souvent judicieux de mettre dans les pages d’erreur de production du contenu purement statique.
En-têtes de réponse
Une fois les en-têtes d’une réponse envoyés :
- L’application ne peut pas modifier le code d’état de la réponse.
- Il est impossible d’exécuter les pages d’exception ou les gestionnaires. La réponse doit être accomplie ou la connexion abandonnée.
Gestion des exceptions de serveur
En plus de la logique de gestion des exceptions de votre application, l’implémentation de serveur HTTP peut gérer certaines exceptions. Si le serveur intercepte une exception avant que les en-têtes de réponse ne soient envoyés, le serveur envoie une réponse 500 Erreur interne du serveur sans corps de réponse. Si le serveur intercepte une exception une fois que les en-têtes de réponse ont été envoyés, il ferme la connexion. Les demandes qui ne sont pas gérées par votre application sont gérées par le serveur. Toute exception qui se produit tandis que le serveur traite la demande est gérée par le dispositif de gestion des exceptions du serveur. Ni les pages d’erreur personnalisées de l’application, ni les intergiciels (middleware) de gestion des exceptions, ni les filtres n’ont d’incidence sur ce comportement.
Gestion des exceptions de démarrage
Seule la couche d’hébergement peut gérer les exceptions qui se produisent au démarrage de l’application. L’hôte peut être configuré pour capturer les erreurs de démarrage et capturer les erreurs détaillées.
La couche d’hébergement ne peut afficher la page d’une erreur de démarrage capturée que si celle-ci se produit une fois la liaison établie entre l’adresse d’hôte et le port. Si la liaison échoue :
- La couche d’hébergement journalise une exception critique.
- Le processus dotnet tombe en panne.
- Aucune page d’erreur n’est affichée lorsque le serveur HTTP est Kestrel.
En cas d’exécution sur IIS (ou Azure App Service) ou IIS Express, une réponse 502.5 - Échec du processus est retournée par le module ASP.NET Core si le processus ne peut pas démarrer. Pour plus d’informations, consultez Résoudre les problèmes d’ASP.NET Core sur Azure App Service et IIS.
Page d’erreur de base de données
Le middleware de page d’erreur de base de données capture les exceptions liées à la base de données qui peuvent être résolues à l’aide de migrations Entity Framework. Lorsque ces exceptions se produisent, une réponse HTML comportant le détail des actions possibles pour résoudre le problème est générée. Cette page ne doit être activée que dans l’environnement de développement. Pour cela, ajoutez du code à Startup.Configure
:
if (env.IsDevelopment())
{
app.UseDatabaseErrorPage();
}
UseDatabaseErrorPage nécessite le package NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore .
Filtres d’exceptions
Dans les applications MVC, vous pouvez configurer les filtres d’exception globalement, contrôleur par contrôleur ou action par action. Dans Razor les applications Pages, elles peuvent être configurées globalement ou par modèle de page. Ces filtres gèrent les exceptions non prises en charge qui se produisent pendant l’exécution d’une action de contrôleur ou d’un autre filtre. Pour plus d’informations, consultez Filtres dans ASP.NET Core.
Conseil
Les filtres d’exceptions sont utiles pour intercepter les exceptions qui se produisent dans les actions MVC, mais n’offrent pas la même souplesse que le middleware de gestion des exceptions. Nous vous recommandons d’utiliser le middleware. N’utilisez des filtres que si vous devez gérer les erreurs différemment en fonction de l’action MVC choisie.
Erreurs d’état de modèle
Pour plus d’informations sur la gestion des erreurs d’état de modèle, voir Liaison de modèles et Validation de modèles.