共用方式為


處理 ASP.NET 核心 API 中的錯誤

備註

這不是本文的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本

警告

此版本的 ASP.NET Core 已不再受支援。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援政策。 如需目前的版本,請參閱 本文的 .NET 9 版本

本文說明如何處理 ASP.NET 核心 API 中的錯誤。 已選取 [最小 API] 的檔案。 若要查看控制器型 API 的文件,請選取 [控制器] 索引標籤。如需 Blazor 錯誤處理指引,請參閱 處理 ASP.NET Core Blazor 應用程式中的錯誤

開發人員例外頁面

開發人員例外狀況頁面會顯示未處理要求例外狀況的詳細資訊。 它用來 DeveloperExceptionPageMiddleware 從 HTTP 管線擷取同步和非同步例外狀況,並產生錯誤回應。 開發人員例外狀況頁面會在中介軟體管線的早期執行,因此它可以攔截後面的中介軟體中擲回的未處理例外狀況。

ASP.NET Core 應用程式預設會在下列情況下啟用開發人員例外頁面:

使用舊版範本建立的應用程式,亦即使用 WebHost.CreateDefaultBuilder,可以透過呼叫 app.UseDeveloperExceptionPage來啟用開發人員例外狀況頁面。

警告

除非 應用程式在開發環境中執行,否則請勿啟用開發人員例外狀況頁面。 當應用程式在生產環境中執行時,請勿公開共用詳細的例外狀況資訊。 如需配置環境的相關資訊,請參閱 ASP.NET Core 執行時期環境

開發人員例外狀況頁面可以包含例外狀況和要求的下列相關資訊:

  • 堆疊追蹤
  • 查詢字串參數 (如果有的話)
  • Cookies(如有)
  • Headers
  • 端點中繼資料 (如果有的話)

開發人員例外狀況頁面不保證提供任何資訊。 使用 記錄來 取得完整的錯誤資訊。

下圖顯示範例開發人員例外狀況頁面,其中包含動畫,以顯示索引標籤和顯示的資訊:

開發人員例外狀況頁面會以動畫形式顯示選取的每個索引標籤。

為了回應具有標頭的要求 Accept: text/plain ,開發人員例外狀況頁面會傳回純文字,而不是 HTML。 例如:

Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
   at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
   at lambda_method1(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f

若要在最小 API 中查看開發人員例外狀況頁面:

  • 開發環境中執行範例應用程式。
  • 移至 /exception 端點。

本節參考下列範例應用程式,以示範在最小 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();

例外狀況處理常式

在非開發環境中,請使用 「例外狀況處理常式中介軟體 」來產生錯誤承載。

若要設定 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();

用戶端和伺服器錯誤回應

請考慮下列最小 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);

/users端點會產生 200 OKjson when User is greater idthan 的0表示法,否則是400 BAD REQUEST沒有回應內文的狀態碼。 如需建立回應的詳細資訊,請參閱在 最小 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 核心中建立問題詳細資料。 AddProblemDetails(IServiceCollection)上的IServiceCollection擴充方法會註冊預設IProblemDetailsService實作。

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

可以使用擴充方法,將最小 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 後援

在下列程式碼中, httpContext.Response.WriteAsync("Fallback: An error occurred.") 如果 IProblemDetailsService 實作無法產生 ProblemDetails

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

var app = builder.Build();

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

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

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

app.Run();

上述 程式碼:

  • 如果無法 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();

public record User(int Id);

其他錯誤處理功能

從控制器移轉至最小API

如果您要從控制器型 API 移轉至最小 API:

  1. 動作篩選器取代為端點篩選器或中介軟體
  2. 模型驗證取代為手動驗證或自訂繫結
  3. 異常篩選器取代為異常處理中介軟體
  4. 設定問題詳細資料,以AddProblemDetails()取得一致的錯誤回應

何時使用控制器型錯誤處理

如果您需要,請考慮以控制器為基礎的 API:

  • 複雜的模型驗證案例
  • 跨多個控制器的集中式異常處理
  • 對錯誤回應格式的精細控制
  • 與篩選器和約定等 MVC 功能整合

如需控制器型錯誤處理的詳細資訊,包括驗證錯誤、問題詳細資料自訂和異常狀況篩選器, 請參閱控制器索引 標籤區段。

其他資源