ASP.NET MVCでエラーハンドリングを行う場合
ASP.NET MVCでFilterを使えること自体は皆さん御存知だと思いますし、Usa*Usaさんあたりを見てもらえればよいと思います。が、Exception自体については余り語られていません。Exception系の処理がどう走っているかを軽くまとめて見ます。
まずはまとめから
必要な物として
- Controller に [HandleError]属性を追加 → 無い場合は、Exceptionの発生でアプリケーションが終了する。
- web.config に
を追記 → 無い場合は、そもそもOnExceptionメソッドが動かない
実行順番
- コントローラ内部のアクションを実行
- コントローラクラスのOnException()を実行
- フィルターのOnException()を実行
下準備
- web.config の設定
そもそもの所、web.configで設定してあげないとエラーハンドリングも何もあったもんじゃ有りません。具体的にはMSDNを見てもらうとして、以下な感じでweb.configに設定を追加します。
<configuration> (中略) <system.web> <customErrors mode="On" /> (中略) </system.web> (中略) </configuration>
これでASP .NET MVCでOnException系のイベントが有効になります。
- XXXControllerクラスに HandleErrorAttributeをつける
以下の例に従って、ControllerクラスにExceptionハンドル用属性を付与します。
public class ExceptionController : Controller { // // GET: /Exception/ [HandleError(ExceptionType=typeof(Exception))] public ActionResult Index() { (中略) return View(); }
ここで、HandleErrorAttributeをメソッドに付与していますが、クラスに対しても付与可能です。
サンプルコード
- MyExceptionFilter
フィルタクラス。フィルタ属性と、Exceptionのフィルタインターフェースを継承してます。単にメッセージを吐くだけ。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class MyExceptionFilterAttribute : FilterAttribute, IExceptionFilter { public void OnException(ExceptionContext filterContext) { Trace.WriteLine("MyExceptionFilter:OnException()"); } }
- ExceptionController
コントローラクラス。こいつのIndexアクションにアクセスした場合に、強制的に例外発生させてます。次に、OnExceptionメソッドもオーバーライドしてメッセージ吐いてます。
[MyExceptionFilter] public class ExceptionController : Controller { // // GET: /Exception/ [HandleError(ExceptionType=typeof(Exception))] public ActionResult Index() { Debug.WriteLine("ExceptionController#Index内部"); throw new Exception(@"うはww無理すwwwwww"); return View(); } protected override void OnException(ExceptionContext filterContext) { base.OnException(filterContext); Debug.WriteLine(this.GetType().Name + ":OnException()"); } }
動作確認
実際に動作させてみて、ログのメッセージを確認すると以下の感じになる。その後、アプリケーションの処理は続行。
ExceptionController#Index内部 'System.Exception' の初回例外が MvcApplication1.DLL で発生しました。 ExceptionController:OnException() MyExceptionFilter:OnException()
と、言うことは上でも言いましたが、以下の順番で実行されるということね。
- コントローラ内部のアクションを実行
- コントローラクラスのOnException()を実行
- フィルターのOnException()を実行