ASP.NET Core Tips : 例外をJSONレスポンスに変換するフィルタ実装例

ASP.NET Core の WebAPI、JSONのシリアライズは自動でやってくれるわ Swagger への対応も簡単だわ便利ですよね。
と、調子に乗って作っていると例外を捕まえ忘れた時

exceptionpage.png

みたいな事になります(UseDeveloperExceptionPageを使わないとステータスコードのみの空ページになりますが)。
やはりエラー時はエラー情報を乗せたJSONを返すようにしたいですよね。
というわけで ExceptionFilter を差し込んで Controller 内で捕まえなかった例外を自動的にエラー用のレスポンスJSONに乗せ換えて返してくれるフィルタのサンプルの作り方です。

独自例外の定義

何の例外が発生しても 500 固定にするならそれはそれでいいんですが、やはりステータスコードやメッセージをある程度制御したい事もあるので、独自の例外を定義します。

public class APIException : Exception {
    public int StatusCode_ = 500;
    ...

    public APIException(int statusCode, string message,
        [CallerMemberName] string memberName = "",
        [CallerFilePath] string sourceFilePath = "",
        [CallerLineNumber] int sourceLineNumber = 0
        )
        : this(message, memberName, sourceFilePath, sourceLineNumber) {
        StatusCode_ = statusCode;
    }
    ...
}

フィルタの実装

ExceptionFilterAttribute から派生したフィルタの実装を行います。

public class APIExceptionFilter : ExceptionFilterAttribute {
    public override void OnException(ExceptionContext context) {
        JsonResult result;

        if (context.Exception is APIException) {
            var ex = context.Exception as APIException;

            result = new JsonResult(new {
                StatusCode = ex.StatusCode_,
                ex.Message
            }) {
                StatusCode = ex.StatusCode_
            };
        } else {
            result = new JsonResult(new {
                StatusCode = 500,
                context.Exception.Message
            }) {
                StatusCode = 500
            };
        }

        context.Result = result;
    }
}

捕まえた例外の型が APIException だった時はそのステータスコードとメッセージから、APIException 以外だった時はステータスコード 500と、例外のメッセージからレスポンスを作成するようにします。

フィルタの使用

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<APIExceptionFilter>();
}
[ServiceFilter(typeof(APIExceptionFilter))]
public class ValuesController : Controller
{
    ...
    // GET api/values/ArgumentNullException
    [HttpGet("ArgumentNullException")]
    public string GetArgumentNullException() {
        throw new ArgumentNullException("ArgumentNullException");
    }

    // GET api/values/APIException
    [HttpGet("APIException")]
    public string GetAPIException() {
        throw new APIException(HttpStatusCode.BadRequest, "Your exception message");
    }
}

ConfigureServices でフィルタを ServiceCollection に追加し、Controller でフィルタの使用を宣言します。
Controller で処理しない例外があった場合、フィルタで処理したレスポンスのJSONが返されます。

サンプルソース

サンプルはこちら

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.