注
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 10 バージョンを参照してください。
Warnung
このバージョンの ASP.NET Coreはサポートされなくなりました。 詳細については、.NETおよびコア サポート ポリシー.NETを参照してください。 現在のリリースについては、この記事の .NET 10 バージョンを参照してください。
この記事では、ASP.NET Core API のエラーを処理する方法について説明します。 最小限の API のドキュメントが選択されています。 コントローラー ベースの API のドキュメントを表示するには、Controllers タブを選択します。Blazor エラー処理のガイダンスについては、 ASP.NET Core Blazor アプリでのハンドル エラーを参照してください。
開発者例外ページ
"開発者例外ページ" には、未処理の要求の例外に関する詳細な情報が表示されます。 DeveloperExceptionPageMiddleware を使用して、HTTP パイプラインから同期および非同期例外をキャプチャし、エラー応答を生成します。 開発者例外ページは、後続のミドルウェアでスローされた未処理の例外をキャッチできるように、ミドルウェア パイプラインの早い段階で実行されます。
ASP.NET Coreアプリでは、次の両方の場合に開発者例外ページが既定で有効になります。
-
Development環境で実行されています。 - アプリが現在のテンプレート、つまり WebApplication.CreateBuilder を使用して作成された。
以前のテンプレート、つまり WebHost.CreateDefaultBuilder を使用して作成されたアプリは、app.UseDeveloperExceptionPage を呼び出すことによって開発者例外ページを有効にすることができます。
Warnung
Development環境でアプリが実行されている場合を除き、開発者例外ページを有効にしないでください。 アプリが運用環境で実行されている場合は、詳細な例外情報をパブリックに共有しないでください。 環境の構成の詳細については、「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 で開発者例外ページを表示するには:
-
Development環境でサンプル アプリを実行します。 -
/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 OK が json より大きい場合、User の id 表現を持つ 0 を返し、それ以外の場合はレスポンス本文を含まない 400 BAD REQUEST ステータス コードを返します。 応答の作成の詳細については、「 最小限の API アプリで応答を作成する」を参照してください。
Status Code Pages middlewareは、すべての HTTP クライアント (400-) またはサーバー (499500 -) の応答に対して、599に共通の本文内容を生成するように構成できます。 ミドルウェアは、 UseStatusCodePages 拡張メソッドを呼び出すことによって構成されます。
たとえば、次の例では、ルーティング エラー ( など) を含むすべてのクライアントとサーバーの応答について、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 のエラーを報告するために使用されます。
問題の詳細サービスは、ASP.NET Coreでの問題の詳細の作成をサポートする IProblemDetailsService インターフェイスを実装します。
AddProblemDetails(IServiceCollection) の IServiceCollection 拡張メソッドは、既定の IProblemDetailsService 実装を登録します。
ASP.NET Core アプリでは、AddProblemDetails が呼び出されたときに、次のミドルウェアによって問題の詳細 HTTP 応答が生成されます。ただし、Accept 要求 HTTP ヘッダーには、登録済みの IProblemDetailsWriter でサポートされているコンテンツ タイプの 1 つが含まれていません (既定値: application/json)。
- ExceptionHandlerMiddleware: カスタム ハンドラーが定義されていない場合に、問題の詳細の応答を生成します。
- StatusCodePagesMiddleware: 既定で問題の詳細の応答を生成します。
-
DeveloperExceptionPageMiddleware: 開発中に
Accept要求 HTTP ヘッダーにtext/htmlが含まれていない場合に、問題の詳細応答を生成します。
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 フォールバック
次のコードでは、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 要求ヘッダー が、DefaultProblemDetailsWriterがサポートしていないメディアの種類を指定するエンドポイントです。 - 例外ハンドラー ミドルウェアを使用します。
注
DefaultProblemDetailsWriterでは、Accept要求ヘッダーで次のメディアの種類がサポートされています。
application/jsonapplication/problem+json-
*/*やapplication/*のようなワイルドカード型
application/xmlやtext/htmlなどの JSON 以外のメディアの種類はサポートされておらず、フォールバック動作がトリガーされます。
次の例は、 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 に移行する場合:
- アクション フィルターをエンドポイント フィルターまたはミドルウェアに置き換える
- モデルの検証を手動検証またはカスタム バインドに置き換える
- 例外フィルターを例外処理ミドルウェアに置き換える
-
を使用して一貫したエラー応答を実現するために、
AddProblemDetails()
コントローラー ベースのエラー処理を使用する場合
必要に応じて、コントローラー ベースの API を検討してください。
- 複雑なモデル検証シナリオ
- 複数のコントローラー間での一元的な例外処理
- エラー応答の書式設定をきめ細かく制御する
- フィルターや規則などの MVC 機能との統合
検証エラー、問題の詳細のカスタマイズ、例外フィルターなど、コントローラーベースのエラー処理の詳細については、「 コントローラー 」タブのセクションを参照してください。
関連するコンテンツ
ASP.NET Core