相关文章推荐
聪明的手电筒  ·  vue Openlayers ...·  2 周前    · 
近视的遥控器  ·  在.Net Core ...·  2 周前    · 
潇洒的饼干  ·  2022网刃杯CTF - REVERSE ...·  10 月前    · 
开心的海豚  ·  WPF ...·  1 年前    · 

本部分引用以下最小 API 应用,以演示处理异常的几种方法。 请求终结点 /exception 时,它会引发异常:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });
app.Run();

开发人员异常页

开发人员异常页显示服务器错误的详细堆栈跟踪。 它使用 DeveloperExceptionPageMiddleware 来捕获 HTTP 管道中的同步和异步异常,并生成错误响应。

ASP.NET Core 应用在以下情况下默认启用开发人员异常页:

  • 开发环境中运行。
  • 应用正在使用 WebApplication.CreateBuilder
  • 有关配置中间件的详细信息,请参阅最小 API 应用中的中间件

    使用上述最小 API 应用时,当 Developer Exception Page 检测到未处理的异常时,它会生成类似以下示例的默认纯文本响应:

    HTTP/1.1 500 Internal Server Error
    Content-Type: text/plain; charset=utf-8
    Date: Thu, 27 Oct 2022 18:00:59 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
        System.InvalidOperationException: Sample Exception
        at Program.<>c.<<Main>$>b__0_1() in ....:line 17
        at lambda_method2(Closure, Object, HttpContext)
        at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
        --- End of stack trace from previous location ---
        at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
    HEADERS
    =======
    Accept: */*
    Connection: keep-alive
    Host: localhost:5239
    Accept-Encoding: gzip, deflate, br
    

    仅当应用在开发环境中运行时才启用“开发人员异常页”。 当应用在生产环境中运行时,切勿公开共享详细的异常信息。 有关配置环境的详细信息,请参阅在 ASP.NET Core 中使用多个环境

    异常处理程序

    在非开发环境中,使用异常处理程序中间件来生成错误有效负载。 若要配置 Exception Handler Middleware,请调用 UseExceptionHandler

    例如,以下代码将应用更改为使用符合 RFC 7807 的有效负载响应客户端。 有关详细信息,请参阅问题详细信息部分。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.UseExceptionHandler(exceptionHandlerApp 
        => exceptionHandlerApp.Run(async context 
            => await Results.Problem()
                         .ExecuteAsync(context)));
    app.Map("/exception", () 
        => { throw new InvalidOperationException("Sample Exception"); });
    app.Run();
    

    客户端和服务器错误响应

    请考虑以下最小 API 应用。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.Map("/users/{id:int}", (int id) 
        => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
    app.Run();
    public record User(int Id);
    

    id 大于 0 时,终结点 /users 生成 200 OK,其中 json 的表现形式为 User,否则 400 BAD REQUEST 状态代码无响应正文。 有关创建响应的详细信息,请参阅在最小 API 应用中创建响应

    对于所有 HTTP 客户端 (400-499) 或服务器 (500 -599) 响应,可配置 Status Code Pages middleware 以生成常见的正文内容(若为空)。 中间件是通过调用 UseStatusCodePages 扩展方法配置的。

    例如,以下示例将应用更改为针对所有客户端和服务器响应使用符合 RFC 7807 的有效负载响应客户端,包括路由错误(例如:404 NOT FOUND)。 有关详细信息,请参阅问题详细信息部分。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.UseStatusCodePages(async statusCodeContext 
        =>  await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                     .ExecuteAsync(statusCodeContext.HttpContext));
    app.Map("/users/{id:int}", (int id) 
        => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
    app.Run();
    public record User(int Id);
    

    问题详细信息

    问题详细信息并不是描述 HTTP API 错误的唯一响应格式,但它们通常用于报告 HTTP API 的错误。

    问题详细信息服务实现 IProblemDetailsService 接口,该接口支持在 ASP.NET Core 中创建问题详细信息。 IServiceCollection 上的 AddProblemDetails 扩展方法注册默认 IProblemDetailsService 实现。

    在 ASP.NET Core 应用中,下列中间件会在调用 AddProblemDetails 时生成问题详细信息 HTTP 响应,除非 Accept 请求 HTTP 标头不包含注册的 IProblemDetailsWriter 支持的内容类型之一(默认:application/json):

  • ExceptionHandlerMiddleware:未定义自定义处理程序时生成问题详细信息响应。
  • StatusCodePagesMiddleware:默认生成问题详细信息响应。
  • DeveloperExceptionPageMiddleware:当 Accept 请求 HTTP 标头不包含 text/html 时,在开发中生成问题详细信息响应。
  • 可以使用 AddProblemDetails 扩展方法,将最小 API 应用配置为针对尚未包含正文内容的所有 HTTP 客户端和服务器错误响应生成问题详细信息响应

    以下代码配置应用以生成问题详细信息:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddProblemDetails();
    var app = builder.Build();
    app.UseExceptionHandler();
    app.UseStatusCodePages();
    app.Map("/users/{id:int}", (int id) 
        => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
    app.Map("/exception", () 
        => { throw new InvalidOperationException("Sample Exception"); });
    app.Run();
    

    有关使用 AddProblemDetails 的详细信息,请参阅问题详细信息

    IProblemDetailsService 回退

    在下面的代码中,如果 IProblemDetailsService 实现无法生成 ProblemDetails,则 httpContext.Response.WriteAsync("Fallback: An error occurred.") 返回错误:

    var builder = WebApplication.CreateBuilder(args); builder.Services.AddProblemDetails(); var app = builder.Build(); app.UseExceptionHandler(exceptionHandlerApp => exceptionHandlerApp.Run(async httpContext => var pds = httpContext.RequestServices.GetService<IProblemDetailsService>(); if (pds == null || !await pds.TryWriteAsync(new() { HttpContext = httpContext })) // Fallback behavior await httpContext.Response.WriteAsync("Fallback: An error occurred."); app.MapGet("/exception", () => throw new InvalidOperationException("Sample Exception"); app.MapGet("/", () => "Test by calling /exception"); app.Run();

    前面的代码:

  • 如果 problemDetailsService 无法编写 ProblemDetails,则使用回退代码编写错误消息。 例如,一个终结点,其中 Accept 请求头指定 DefaulProblemDetailsWriter 不支持的媒体类型。
  • 使用异常处理程序中间件
  • 下面的示例与前面的示例类似,只不过它调用了 Status Code Pages middleware

    var builder = WebApplication.CreateBuilder(args); builder.Services.AddProblemDetails(); var app = builder.Build(); app.UseStatusCodePages(statusCodeHandlerApp => statusCodeHandlerApp.Run(async httpContext => var pds = httpContext.RequestServices.GetService<IProblemDetailsService>(); if (pds == null || !await pds.TryWriteAsync(new() { HttpContext = httpContext })) // Fallback behavior await httpContext.Response.WriteAsync("Fallback: An error occurred."); app.MapGet("/users/{id:int}", (int id) => return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)); app.MapGet("/", () => "Test by calling /users/{id:int}"); app.Run();

    本文介绍如何处理最小 API 应用中的错误。

    在最小 API 应用中,可使用两种不同的内置集中式机制来处理未经处理的异常:

  • 开发人员异常页中间件(仅在开发环境下使用。)
  • 异常处理程序中间件
  • 本部分引用以下最小 API 应用,以演示处理异常的几种方法。 请求终结点 /exception 时,它会引发异常:

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.Map("/exception", () 
        => { throw new InvalidOperationException("Sample Exception"); });
    app.Run();
    

    开发人员异常页

    开发人员异常页显示服务器错误的详细堆栈跟踪。 它使用 DeveloperExceptionPageMiddleware 来捕获 HTTP 管道中的同步和异步异常,并生成错误响应。

    ASP.NET Core 应用在以下情况下默认启用开发人员异常页:

  • 开发环境中运行。
  • 应用正在使用 WebApplication.CreateBuilder
  • 有关配置中间件的详细信息,请参阅最小 API 应用中的中间件

    使用上述最小 API 应用时,当 Developer Exception Page 检测到未处理的异常时,它会生成类似以下示例的默认纯文本响应:

    HTTP/1.1 500 Internal Server Error
    Content-Type: text/plain; charset=utf-8
    Date: Thu, 27 Oct 2022 18:00:59 GMT
    Server: Kestrel
    Transfer-Encoding: chunked
        System.InvalidOperationException: Sample Exception
        at Program.<>c.<<Main>$>b__0_1() in ....:line 17
        at lambda_method2(Closure, Object, HttpContext)
        at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
        --- End of stack trace from previous location ---
        at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
    HEADERS
    =======
    Accept: */*
    Connection: keep-alive
    Host: localhost:5239
    Accept-Encoding: gzip, deflate, br
    

    仅当应用在开发环境中运行时才启用“开发人员异常页”。 当应用在生产环境中运行时,切勿公开共享详细的异常信息。 有关配置环境的详细信息,请参阅在 ASP.NET Core 中使用多个环境

    异常处理程序

    在非开发环境中,使用异常处理程序中间件来生成错误有效负载。 若要配置 Exception Handler Middleware,请调用 UseExceptionHandler

    例如,以下代码将应用更改为使用符合 RFC 7807 的有效负载响应客户端。 有关详细信息,请参阅问题详细信息部分。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.UseExceptionHandler(exceptionHandlerApp 
        => exceptionHandlerApp.Run(async context 
            => await Results.Problem()
                         .ExecuteAsync(context)));
    app.Map("/exception", () 
        => { throw new InvalidOperationException("Sample Exception"); });
    app.Run();
    

    客户端和服务器错误响应

    请考虑以下最小 API 应用。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.Map("/users/{id:int}", (int id) 
        => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
    app.Run();
    public record User(int Id);
    

    id 大于 0 时,终结点 /users 生成 200 OK,其中 json 的表现形式为 User,否则 400 BAD REQUEST 状态代码无响应正文。 有关创建响应的详细信息,请参阅在最小 API 应用中创建响应

    对于所有 HTTP 客户端 (400-499) 或服务器 (500 -599) 响应,可配置 Status Code Pages middleware 以生成常见的正文内容(若为空)。 中间件是通过调用 UseStatusCodePages 扩展方法配置的。

    例如,以下示例将应用更改为针对所有客户端和服务器响应使用符合 RFC 7807 的有效负载响应客户端,包括路由错误(例如:404 NOT FOUND)。 有关详细信息,请参阅问题详细信息部分。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.UseStatusCodePages(async statusCodeContext 
        =>  await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                     .ExecuteAsync(statusCodeContext.HttpContext));
    app.Map("/users/{id:int}", (int id) 
        => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
    app.Run();
    public record User(int Id);
    

    问题详细信息

    问题详细信息并不是描述 HTTP API 错误的唯一响应格式,但它们通常用于报告 HTTP API 的错误。

    问题详细信息服务实现 IProblemDetailsService 接口,该接口支持在 ASP.NET Core 中创建问题详细信息。 IServiceCollection 上的 AddProblemDetails 扩展方法注册默认 IProblemDetailsService 实现。

    在 ASP.NET Core 应用中,下列中间件会在调用 AddProblemDetails 时生成问题详细信息 HTTP 响应,除非 Accept 请求 HTTP 标头不包含注册的 IProblemDetailsWriter 支持的内容类型之一(默认:application/json):

  • ExceptionHandlerMiddleware:未定义自定义处理程序时生成问题详细信息响应。
  • StatusCodePagesMiddleware:默认生成问题详细信息响应。
  • DeveloperExceptionPageMiddleware:当 Accept 请求 HTTP 标头不包含 text/html 时,在开发中生成问题详细信息响应。
  • 可以使用 AddProblemDetails 扩展方法,将最小 API 应用配置为针对尚未包含正文内容的所有 HTTP 客户端和服务器错误响应生成问题详细信息响应

    以下代码配置应用以生成问题详细信息:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddProblemDetails();
    var app = builder.Build();
    app.UseExceptionHandler();
    app.UseStatusCodePages();
    app.Map("/users/{id:int}", (int id) 
        => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
    app.Map("/exception", () 
        => { throw new InvalidOperationException("Sample Exception"); });
    app.Run();
    

    有关使用 AddProblemDetails 的详细信息,请参阅问题详细信息