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 Exception du développeur affiche des informations détaillées sur les exceptions de requête non prises en charge. ASP.NET Core applications activent la page d’exception développeur par défaut lorsque les deux :

La page d’exception du développeur s’exécute au début du pipeline middleware, de sorte qu’elle peut intercepter les exceptions non prises en charge levées dans le 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 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 :

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 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 utilisez OnPost 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 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 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 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. 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 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 :

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 pour les 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 pour les 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 les 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 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.

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 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);
        }
    }
}

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

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 des options suivantes :

  1. Utilisez ProblemDetailsOptions.CustomizeProblemDetails.
  2. Utiliser un personnalisé IProblemDetailsWriter
  3. Appeler dansIProblemDetailsService 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 des 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 Exception du développeur affiche des informations détaillées sur les exceptions de requête non prises en charge. ASP.NET Core applications activent la page d’exception développeur par défaut lorsque les deux :

La page d’exception du développeur s’exécute au début du pipeline middleware, de sorte qu’elle peut intercepter les exceptions non prises en charge levées dans le 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 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 :

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 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 utilisez OnPost 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 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 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 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. 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 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 :

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 pour les 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 pour les 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 les 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 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.

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 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);
        }
    }
}

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 la 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 de 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 l’intergiciel 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. (Comment 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 d’exception du développeur affiche des informations détaillées sur les exceptions de demande non gérée. 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 mis en surbrillance précédent active la page d’exception du développeur lorsque l’application est en cours d’exécution dans l’environnement de développement.

Les modèles placent UseDeveloperExceptionPage tôt dans le pipeline d’intergiciels afin qu’ils puissent intercepter les exceptions non gérées levées dans l’intergiciel (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 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 :

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 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 utilisez OnPost 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>(); dans Program.cs.
  • Sélectionnez Déclencher une exception dans 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>(); dans Program.cs.
  • Sélectionnez Déclencher une exception dans la page d’accueil.

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 fournir des pages de codes d’état, utilisez l’intergiciel des pages de codes 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 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. 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>(); dans Program.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. (Comment 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 est en cours d’exécution dans l’environnement de développement.

Les modèles placent UseDeveloperExceptionPage avant tout intergiciel afin que les exceptions soient interceptées dans l’intergiciel qui suit.

Le code précédent active la page d’exception du développeur uniquement lorsque l’application est en cours d’exécution 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 d’exception 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écuta la requête vers /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 Erreur 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, await context.Response.WriteAsync(new string(' ', 512)); est ajouté afin que le navigateur Internet Explorer affiche le message d’erreur plutôt qu’un message d’erreur Internet Explorer. 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, en accédant à 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 le modèle d’URL de PathBasel’application. 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 de 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. Vérifiez que UseStatusCodePagesWithReExecute est placé avant UseRouting afin que la demande puisse être redirigée vers la page d’état. Pour obtenir un Razor exemple de 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 codes d’état pour un contrôleur MVC ou une méthode d’action, utilisez l’attribut [SkipStatusCodePages] .

Pour désactiver les pages de codes 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.

Ressources supplémentaires