共用方式為


處理 ASP.NET Core API 中的錯誤

備註

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

警告

此版本的 ASP.NET Core 已不再支援。 欲了解更多資訊,請參閱.NET及.NET核心支援政策。 關於目前版本,請參閱本文的 .NET 10 版本

  • 最少的 API
  • 控制器

本文說明如何處理 ASP.NET Core API 中的錯誤。 已選取 [最小 API] 的檔案。 若要查看控制器基礎 API 的文件,請選擇 Controllers 標籤。關於 Blazor 錯誤處理指引,請參見 ASP.NET Core Blazor 應用程式中的錯誤處理

開發人員例外頁面

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

ASP.NET Core 應用程式預設啟用開發者例外頁面,當兩者同時:

  • 在環境中運行。
  • 應用程式是使用目前的範本建立的,也就是使用 。

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

警告

除非應用程式在環境中執行,否則不要啟用開發者例外頁面。 當應用程式在生產環境中執行時,請勿公開共用詳細的例外狀況資訊。 欲了解更多關於環境配置的資訊,請參見 ASP.NET Core runtime environments

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

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

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

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

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

為了回應具有標頭的要求 ,開發人員例外狀況頁面會傳回純文字,而不是 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
  • 控制器

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

  • 在環境中執行範例應用程式。
  • 前往端點。

本節參考下列範例應用程式,以示範在最小 API 中處理例外狀況的方法。 當請求該端點時,它會拋出例外:

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

例外狀況處理常式

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

  • 最少的 API
  • 控制器

若要設定 ,請呼叫 。 例如,下列程式碼將應用程式變更為向用戶端回傳符合 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
  • 控制器

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

端點會在某參數大於特定值時返回表示該結果的表示法,否則會返回不含回應內容的狀態碼。 如需建立回應的詳細資訊,請參閱在 最小 API 應用程式中建立回應。

可以 配置為在 空時為所有 HTTP 用戶端 () 或伺服器 () 回應產生通用內文內容。 中介軟體是藉由呼叫 UseStatusCodePages 擴充方法來設定。

舉例來說,下列範例會變更應用程式,以符合 RFC 7807 規範的承載回應用戶端,以回應所有用戶端和伺服器回應,包括路由錯誤 (例如 )。 如需詳細資訊,請參閱 問題詳細資料 一節。

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 中建立問題細節。 上的擴充方法會註冊預設實作。

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

  • :在未定義自訂處理常式時產生問題詳細資料回應。
  • :依預設會產生問題詳細資料回應。
  • 當開發環境中發現 HTTP 請求標頭未包含指定元素時,系統將產生問題詳細資訊回應。
  • 最少的 API
  • 控制器

可以使用擴充方法將最小 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);

如需有關使用 的詳細資訊,請參閱 問題詳細資料

IProblemDetailsService 後備

在以下程式碼中,當實作無法產生所需內容時,將回傳錯誤。

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

上述 程式碼:

  • 如果無法 寫入 ,則會寫入帶有後援代碼的錯誤訊息。 例如,一個端點,其 Accept 請求標頭 指定了媒體類型,而該 媒體類型不被支持。
  • 使用例外處理中介軟體。

備註

在 請求標頭中支援以下媒體類型 :

  • application/json
  • application/problem+json
  • 百用字元類型, 如 和

非 JSON 媒體類型,如 或 , 不 被支援,並會觸發備援行為。

下列範例與上述範例類似,只是它會呼叫 。

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 移轉至最小 API:

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

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

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

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

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

其他資源