結果.問題は、ASP.NET Coreが提供する標準化されたエラー応答生成メソッドで、RFC 7807規格に準拠したエラー応答(問題の詳細)を作成します。これは、Web APIで構造化されたエラー情報を返すために使用され、タイプ、タイトル、ステータス、および詳細などのフィールドを含み、クライアントがエラーを理解し処理するのを助けます。パラメーターカスタマイズを通じて、結果.問題はエラータイプ、ステータスコード、詳細情報、およびインスタンスパスを明確に記述でき、APIの一貫性および保守性を向上させ、クライアントがエラーをより効率的に処理できるようにします。特に、最新のRESTful APIの構築に適しています。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/test", () =>
{
return Results.Problem(type: "Bad Request",
title: "無効な番号",
detail: "番号形式は:N00000、N+5桁の数字",
statusCode: StatusCodes.Status400BadRequest);
});
app.Run();
実行結果:
ProblemDetailsの拡張
以下のコードは、ASP.NET CoreでResults.Problemを拡張して、カスタムの標準化されたエラー応答を生成する方法を示しています。この拡張は、Problem Detailsフォーマットを使用し、エラーの詳細の処理方法をカスタマイズすることで、エラー情報の構造化とデバッグ性を強化します。
まず、builder.Services.AddProblemDetailsを通じてProblem Detailsサービスを登録し、CustomizeProblemDetails構成でProblem Detailsの内容をカスタマイズします。この構成では、エラーインスタンス(Instance)の詳細な形式が指定され、リクエストプロトコル、メソッド、およびパスを含みます。同時に、requestId(リクエストのユニークな識別子)、traceId(トレース識別子)、およびclientIP(クライアントのIPアドレス)などのクライアントリクエストのトレース情報を追加し、エラー応答にコンテキスト情報を持たせます。
カスタム例外タイプをキャッチおよび処理するために、コードはProblemExceptionという名前のカスタム例外クラスを作成しました。このクラスには、特定のエラー情報を保存するためのErrorおよびMessageプロパティがあります。続いて、IExceptionHandlerインターフェースを実装したProblemExceptionHandlerクラスを実装し、このクラスは例外をインターセプトし、ProblemDetailsServiceを通じて標準のProblem Details応答を生成します。この過程で、TryHandleAsyncメソッドはProblemExceptionの例外かどうかを確認し、それがそうであれば、ステータスを400(Bad Request)に設定し、ProblemExceptionインスタンスのErrorおよびMessageプロパティに基づいてTitleおよびDetailフィールドを埋め込んだカスタムのProblemDetailsオブジェクトを作成します。最後に、ProblemDetailsService.TryWriteAsyncメソッドを通じてProblem Detailsを応答に書き込み、クライアントが構造化されたエラー情報を確実に受信できるようにします。
アプリケーション内で、/testというルートを定義し、このルートに対するクライアントリクエスト時にProblemException例外をスローし、カスタムエラー情報を含むProblem Details応答を返します。この方法を通じて、クライアントは詳細なエラーコンテキストおよび構造化されたエラー情報を受信でき、問題を迅速に識別およびデバッグするのに役立ちます。
具体的なコード:
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails(opt =>
{
opt.CustomizeProblemDetails = context =>
{
context.ProblemDetails.Instance = $"{context.HttpContext.Request.Protocol} {context.HttpContext.Request.Method} {context.HttpContext.Request.Path}";
context.ProblemDetails.Extensions.TryAdd("requestId", context.HttpContext.TraceIdentifier);
var activity = context.HttpContext.Features.Get<IHttpActivityFeature>()?.Activity;
context.ProblemDetails.Extensions.TryAdd("traceId", activity?.Id);
if (context.HttpContext.Connection != null && context.HttpContext.Connection.RemoteIpAddress != null)
{
context.ProblemDetails.Extensions.TryAdd("clientIP", context.HttpContext.Connection.RemoteIpAddress?.ToString());
}
};
});
builder.Services.AddExceptionHandler<ProblemExceptionHandler>();
var app = builder.Build();
app.MapGet("/test", () =>
{
throw new ProblemException(error: "無効な番号",
message: "番号形式は:N00000、N+5桁の数字");
});
app.UseExceptionHandler();
app.Run();
public class ProblemException : Exception
{
public string Error { get; }
public ProblemException(string error, string message) : base(message)
{
Error = error;
}
}
public class ProblemExceptionHandler : IExceptionHandler
{
private readonly IProblemDetailsService _problemDetailsService;
public ProblemExceptionHandler(IProblemDetailsService problemDetailsService)
{
_problemDetailsService = problemDetailsService;
}
public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
if (exception is not ProblemException problemException)
{
return true;
}
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status400BadRequest,
Title = problemException.Error,
Detail = problemException.Message,
Type = "Bad Request"
};
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
return await _problemDetailsService.TryWriteAsync(new ProblemDetailsContext
{
HttpContext = httpContext,
ProblemDetails = problemDetails
});
}
}
実装の結果:
実装した際の欠点は、例外がスローされると、プラットフォームが失敗のログを出力することです。
(Translated by GPT)