如何在最少 API 應用程式中處理錯誤

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

透過 David Acker 的貢獻

本文說明如何在最少 API 應用程式中處理錯誤。

例外狀況

在 Minimal API 應用程式中,有兩種​​不同的內建集中機制來處理未處理的例外狀況:

本節參考以下 Minimal API 應用程式來示範處理例外狀況的方法。 當要求 /exception 端點時,它會擲回例外狀況:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

開發人員例外狀況頁面

開發人員例外狀況頁面會顯示詳細的伺服器錯誤堆疊追蹤。 它會使用 DeveloperExceptionPageMiddleware 從 HTTP 管線中擷取同步和非同步例外狀況,並產生錯誤回應。

當符合以下兩項條件時,ASP.NET Core 應用程式預設會啟用開發人員例外狀況頁面:

如需設定中介軟體的詳細資訊,請參閱 Minimal API 應用程式中的中介軟體

使用上述的 Minimal 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.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

用戶端和伺服器錯誤回應

仔細觀察下列 Minimal API 應用程式。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

id 大於 0 時,/users 端點會產生 200 OKUserjson 表示形式,否則會產生 400 BAD REQUEST 狀態碼,沒有回應本文。 如需建立回應的詳細資訊,請參閱在 Minimal API 應用程式中建立回應

Status Code Pages middleware 可以設定成為所有 HTTP 用戶端 (400-499) 或伺服器 (500 -599) 回應產生一般本文內容 (當為空時)。 中介軟體是藉由呼叫 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.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

問題詳細資料

問題詳細資料 並不是描述 HTTP API 錯誤的唯一回應格式,不過,它們通常會用來報告 HTTP API 的錯誤。

問題詳細資料服務會實作 IProblemDetailsService 介面 (其支援在 ASP.NET Core 中建立問題詳細資料)。 IServiceCollection 上的 AddProblemDetails 擴充方法會註冊預設的 IProblemDetailsService 實作。

在 ASP.NET Core 應用程式中,下列中介軟體會在呼叫 AddProblemDetails 時產生問題詳細資料 HTTP 回應,除非 Accept 要求 HTTP 標頭不包含註冊的 IProblemDetailsWriter 所支援的其中一個內容類型 (預設值:application/json):

透過使用 AddProblemDetails 擴充功能方法,可以將 Minimal API 應用程式設定為還沒有本文內容 的所有 HTTP 用戶端和伺服器錯誤回應產生問題詳細資訊回應。

下列程式碼會將應用程式設定為產生問題詳細資料:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

如需使用 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();

上述 程式碼:

下列範例與上述範例類似,不同之處在於它會呼叫 Status Code Pages middleware

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseStatusCodePages(statusCodeHandlerApp =>
{
    statusCodeHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/users/{id:int}", (int id) =>
{
    return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

本文說明如何在最少 API 應用程式中處理錯誤。

例外狀況

在 Minimal API 應用程式中,有兩種​​不同的內建集中機制來處理未處理的例外狀況:

本節參考以下 Minimal 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 應用程式預設會啟用開發人員例外狀況頁面:

如需設定中介軟體的詳細資訊,請參閱 Minimal API 應用程式中的中介軟體

使用上述的 Minimal 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();

用戶端和伺服器錯誤回應

仔細觀察下列 Minimal 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 OKUserjson 表示形式,否則會產生 400 BAD REQUEST 狀態碼,沒有回應本文。 如需建立回應的詳細資訊,請參閱在 Minimal API 應用程式中建立回應

Status Code Pages middleware 可以設定成為所有 HTTP 用戶端 (400-499) 或伺服器 (500 -599) 回應產生一般本文內容 (當為空時)。 中介軟體是藉由呼叫 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):

透過使用 AddProblemDetails 擴充功能方法,可以將 Minimal 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 的詳細資訊,請參閱問題詳細資料