normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

ASP.NET MVCでエラーハンドリングを行う場合

ASP.NET MVCでFilterを使えること自体は皆さん御存知だと思いますし、Usa*Usaさんあたりを見てもらえればよいと思います。が、Exception自体については余り語られていません。Exception系の処理がどう走っているかを軽くまとめて見ます。

まずはまとめから

必要な物として
  • Controller に [HandleError]属性を追加 → 無い場合は、Exceptionの発生でアプリケーションが終了する。
  • web.config に を追記 → 無い場合は、そもそもOnExceptionメソッドが動かない
実行順番
  1. コントローラ内部のアクションを実行
  2. コントローラクラスのOnException()を実行
  3. フィルターの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()

と、言うことは上でも言いましたが、以下の順番で実行されるということね。

  1. コントローラ内部のアクションを実行
  2. コントローラクラスのOnException()を実行
  3. フィルターのOnException()を実行