Minimal API アプリでエラーを処理する方法
Note
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
協力: David Acker
この記事では、Minimal API アプリでエラーを処理する方法について説明します。
例外
Minimal API アプリには、未処理の例外を処理するための 2 つの異なる組み込みの一元化されたメカニズムがあります。
- 開発者例外ページ ミドルウェア (開発環境でのみ使用)。
- 例外ハンドラー ミドルウェア
このセクションでは、次の 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 アプリでは既定で開発者例外ページが有効になります。
- 開発環境で実行している。
- アプリは WebApplication.CreateBuilder を使用しています。
ミドルウェアの構成の詳細については、「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);
/users
エンドポイントは、id
が 0
より大きい場合は User
の json
表現を使用し、それ以外の場合は応答本文のない 400 BAD REQUEST
状態コードを使用して 200 OK
を生成します。 応答の作成の詳細については、「Minimal API アプリで応答を作成する」を参照してください。
Status Code Pages middleware
は、すべての HTTP クライアント (400
-499
) またはサーバー (500
-599
) 応答に対して、空の場合に共通の本文コンテンツを生成するように構成できます。 ミドルウェアは、UseStatusCodePages 拡張メソッドを呼び出すことによって構成されます。
たとえば、次の例では、ルーティング エラー ( など) を含むすべてのクライアントとサーバーの応答に対して、RFC 7807404 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
) によってサポートされるいずれかのコンテンツ タイプが含まれていない場合を除きます。
- ExceptionHandlerMiddleware: カスタム ハンドラーが定義されていない場合に、問題の詳細の応答を生成します。
- StatusCodePagesMiddleware: 既定で問題の詳細の応答を生成します。
- DeveloperExceptionPageMiddleware:
Accept
要求 HTTP ヘッダーにtext/html
が含まれていない場合に、開発中に問題の詳細の応答を生成します。
Minimal API アプリは、AddProblemDetails
拡張メソッドを使用して、"本文のコンテンツがまだない" すべての 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
を書き込めない場合は、フォールバック コードでエラー メッセージを書き込みます。 たとえば、DefaulProblemDetailsWriter
がサポートしていないメディアの種類を Accept 要求ヘッダーで指定するエンドポイントなどです。- 例外ハンドラー ミドルウェアを使います。
次の例は、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);
この記事では、Minimal API アプリでエラーを処理する方法について説明します。
例外
Minimal API アプリには、未処理の例外を処理するための 2 つの異なる組み込みの一元化されたメカニズムがあります。
- 開発者例外ページ ミドルウェア (開発環境でのみ使用)。
- 例外ハンドラー ミドルウェア
このセクションでは、次の 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 アプリでは既定で開発者例外ページが有効になります。
- 開発環境で実行している。
- アプリは WebApplication.CreateBuilder を使用しています。
ミドルウェアの構成の詳細については、「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);
/users
エンドポイントは、id
が 0
より大きい場合は User
の json
表現を使用し、それ以外の場合は応答本文のない 400 BAD REQUEST
状態コードを使用して 200 OK
を生成します。 応答の作成の詳細については、「Minimal API アプリで応答を作成する」を参照してください。
Status Code Pages middleware
は、すべての HTTP クライアント (400
-499
) またはサーバー (500
-599
) 応答に対して、空の場合に共通の本文コンテンツを生成するように構成できます。 ミドルウェアは、UseStatusCodePages 拡張メソッドを呼び出すことによって構成されます。
たとえば、次の例では、ルーティング エラー ( など) を含むすべてのクライアントとサーバーの応答に対して、RFC 7807404 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
が含まれていない場合に、開発中に問題の詳細の応答を生成します。
Minimal API アプリは、AddProblemDetails
拡張メソッドを使用して、"本文のコンテンツがまだない" すべての 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
の使用について詳しくは、「問題の詳細」を参照してください。
ASP.NET Core
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示