ASP.NET Web APIではどのように例外処理を行うべきであろうか? ASP.NET Web APIが提供する例外処理の仕組みと、開発者がカスタマイズできる例外処理について解説する。
アクションメソッド内でHttpResponseMessageExceptionクラスを除く例外クラスが発生すると、ASP.NET Web APIは、スローされた例外クラスを基にHTTPレスポンスを構築しクライアントへ返す*7。
*7 ASP.NET MVCでは、HandleError属性(System.Web.Mvc名前空間)を設定しないとカスタムエラーページが表示されないが、ASP.NET Web APIでは何も設定せずとも例外処理が働く。また、ASP.NET Web APIでHandleError属性を付与してもカスタムエラーページが表示されることはないので注意。
なお、HttpResponseMessageExceptionクラスは、例外時にスローするのではなく、通常のHTTPレスポンスを構築するためにスローするクラスである。
例として次のリスト14のように、とあるアクションメソッドで例外クラスがスローされたとしよう。
public class CustomersController : ApiController
{
public string Get()
{
throw new NotImplementedException("未実装です");
}
}
リスト14のアクションメソッドが呼び出された場合、次の表5のようにHTTPレスポンスが返される。
ステータスコード | 500 Internal Server Error |
---|---|
Body(JSON書式の場合) | {"Message":"エラーが発生しました。", "ExceptionMessage":"未実装です", "ExceptionType":"System.NotImplementedException", "StackTrace":" 場所 MvcApplication4.Controllers.ValuesController.Get()(省略)" } |
例外処理で構築されるHTTPレスポンスにはスタックトレースが含まれている(表5参照)。この情報はデバッグ時には役に立つが、本番環境ではセキュリティ上の問題で表示させたくない場合もある。
このような場合のために、ASP.NET Web APIでは詳細なエラー情報を出力するか否かを選択できるようになっている。詳細なエラー情報とは、先の表5のHTTPレスポンスで言うと、ExceptionMessage、ExceptionType、StackTraceが該当する。
出力するか否かの選択方法は、HttpConfigurationクラスのIncludeErrorDetailPolicyプロパティ(System.Web.Http名前空間のIncludeErrorDetailPolicy列挙型)を設定すればよい。具体的にはWebApiConfig.csで次のリスト15のように設定する。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never;
// ...(省略)
}
}
例えばリスト15のように設定した場合は、HTTPレスポンスのBodyは次の表6のように、Message項目だけが出力される。
ステータスコード | 500 Internal Server Error |
---|---|
Body(JSON書式の場合) | {"Message":"エラーが発生しました。"} |
表6 詳細なエラー情報を「出力しない」とした場合に返されるHTTPレスポンス |
IncludeErrorDetailPolicy列挙体と、それぞれの列挙子を選択した場合の、詳細なエラー情報の出力有無については、「MSDN:IncludeErrorDetailPolicy 列挙体」に記載されているので参考にしてほしい。
以上がASP.NET Web APIによる例外処理の仕組みである。次は、開発者が行うことができる例外処理について解説する。
例外フィルター属性を利用することで、例外処理のカスタマイズを行える。例えば、例外クラスの種類によってそれぞれ別の内容のHTTPレスポンスを構築する、といったことや、データベース更新の競合時に発生する例外クラスを利用してHTTPレスポンスを構築する、といったことが可能となる。
具体的な実装手順を見てみよう。次のリスト16は、NotImplementedException例外クラスがスローされたときの対処を実装した例外フィルター属性クラスだ。ステータスコード「501 Not Implemented」とBodyに例外クラスの情報を格納したHTTPレスポンスを返すよう実装している。
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
namespace MvcApplication4.Models
{
public class CustomizeExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
//スローされた例外を取得します
Exception ex = actionExecutedContext.Exception;
if (ex is NotImplementedException)
{
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.NotImplemented, ex);
}
}
}
}
次にこの例外処理フィルター属性を、適用したいレベルに合わせて、アクションメソッドに付与する(次のリスト17)*8。この場合、付与したアクションメソッド内で例外クラスがスローされた場合のみ、例外クラスフィルタ属性の処理が呼び出される。
*8 フィルター属性は、3つのレベル(アプリケーション内のアクションメソッド全て、とあるAPIコントローラークラス内のみ、とあるアクションメソッドのみの3つ)に合わせて適用できる。
public class CustomerController : ApiController
{
[CustomizeExceptionFilter]
public string Get();
}
以上で、例外フィルター属性による例外処理のカスタマイズは終了だ。また、リスト16のようにCreateErrorResponseメソッドを使った場合でも、前の章で述べた詳細なエラー情報の出力の制御は有効となる。アクションメソッドでTry Catch句が頻出するようであれば、ぜひこの例外処理フィルター属性の利用を検討してみてほしい。
今回は、ルーティングの設定、DataAnnotations属性による検証、例外処理について解説を行った。ASP.NET Web APIの基礎機能の紹介は、今回でおしまいとさせていただく。
次回は、認証と拡張機能について紹介する予定だ。お楽しみに。
Copyright© Digital Advantage Corp. All Rights Reserved.