読者です 読者をやめる 読者になる 読者になる

miso_soup3 Blog

主に ASP.NET 関連について書いています。

エラーが起きたらどうなるか? Application_Error()と、HandleErrorAttribute

ASP.NET ASP.NET MVC

MVCでカスタムエラーページを実装しようとした時、
調べると以下の2つのコードに到着すると思います。

  • Web.Config にて
<customErrors mode="On" defaultRedirect="~/Error/ErrorDayo" >
</customErrors>
  • Glogal.asax.cs にて
filters.Add(new HandleErrorAttribute());
// (またはControllerクラスにて [HandleError])

これらの実装は、ASP.NET の機能と、ASP.NET MVC の機能、2つの要素が関わっています。
この2つを区別しないと、思った通りにエラーページが表示されなかったり、
エラー時の対応処理を行えない場合があります。

今日は、この2つを区別するために、
エラーが起きた時、どのような流れでエラーページに行くのか、
確認してみようと思います。

確認方法

エラーが起きた時、どこに処理が行くのか順番に確認します。
MVCのパイプライン内(Controller内)でおきたエラーと、
MVC以外の場所でエラーが起きた場合で確認します。

CustomErrors mode = "On" の時

前提

以下のようにした場合の、エラー時の流れを追います。
Web.Config

<customErrors mode="On" defaultRedirect="~/Error/ErrorDayo" >
</customErrors>

Glogal.asax.cs

filters.Add(new HandleErrorAttribute());
1. "On" & MVCのパイプライン内(Controller内)でエラー発生時
  • 1. 例えば、Controllerのアクションメソッド内にてエラーが発生。
  • 2. フィルター属性HandleErrorAttributeクラスの、OnExceptionメソッドへ。
  • 3. OnExceptionメソッド内では、"Error"というViewを返すよう記述してある。
  • 4. "Error"というViewを探し、ユーザにエラーページが出力される。

流れは以上です。MVCでの一般的なエラー対処です。
この時のポイントは3つあります。

  • エラーページは、リダイレクトで表示されたものではない。
  • WebConfigで設定したdefaultRedirect="~/Error/ErrorDayo" は全く関係ない。
  • Global.asax(HttpApplication)の、Application_Error()メソッドは呼び出されない。

↓おまけのMVCソースコード、OnExceptionメソッド内の一部。

filterContext.Result = new ViewResult {
	ViewName = View, //← デフォルトでは"Error"
	MasterName = Master,
	ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
	TempData = filterContext.Controller.TempData
};

↓同じくOnExceptionメソッド内のなんだか怪しいコード

// Certain versions of IIS will sometimes use their own error page when
// they detect a server error. Setting this property indicates that we
 // want it to try to render ASP.NET MVC's error page instead.
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
2. "On" & MVCのパイプライン以外のエラー発生時

次は、Controller以外でエラーが発生した時です。

  • 1. 例えば、カスタムControllerFactory内にてエラーが発生。
  • 2. Global.asaxのApplication_Error()メソッドへ。
  • 3. WebConfigで、mode="On" defaultRedirect="~/Error/ErrorDayo" と書いてあるので、~/Error/ErrorDayoへリダイレクト
  • 4. ~/Error/ErrorDayoへアクセスされたので、それに対応するコントローラのアクションメソッドが実行される
  • 5. ちゃんとアクションメソッドとViewが実装されていれば、エラーページ表示でめでたし。

流れは以上です。
ポイントは3つあります。

  • defaultRedirectに設定したURLにリダイレクトすることで、エラーページが表示される。
  • フィルター属性HandleErrorAttributeクラスは、関係ない。
  • エラーページを表示するために、普段と同じようコントローラとViewが呼び出される。(静的な.Htmlも呼び出し可能)

CustomErrors mode = "Off" の時

前提

次は、WebConfigにて、CustomErrors mode = "Off" と設定した時の流れを追います。
先ほどのOnと同じく、HandleErrorAttributeクラスは登録したものとします。

3. "Off" & MVCのパイプライン内(Controller内)でエラー発生時
  • 1. 例えば、Controllerのアクションメソッド内にてエラーが発生。
  • 2. フィルター属性HandleErrorAttributeクラスの、OnExceptionメソッドへ。
  • 3. OnExceptionメソッド内では、"Error"というViewを返すよう記述してある。
  • 4. でも、CustomErrors mode = "Off"がそれを許してくれない。
  • 5. Global.asaxのApplication_Error()メソッドへ。
  • 6. IISのエラーページが表示される。

ポイントは

  • CustomErrors mode = "Off" でも、HandleErrorAttributeクラスに処理が行く事。

です。

4. "Off" & MVCのパイプライン以外のエラー発生時

Controller以外でのエラーの時も、③と同じく、IISのエラーページが表示されます。
CustomErrors mode = "Off" だと、IISのエラーページが表示される、と覚えるとOKだと思います。
2つの違いは、MVCのHandleErrorAttributeクラスがキャッチしてくれるかどうかです。

おしまい。

以上、エラー発生時の流れを追ってみました。
覚えておきたいことは、下の4つです。

  • HandleErrorAttributeクラスは、MVCフレームワークの機能であること
    • そして、エラーを扱うけど、元はただのフィルター属性であること
  • WebConfigのCustomErrors は、MVCではなくASP.NETの機能であること
  • WebConfigのdefaultRedirectは、URLにリダイレクトする、というWEBの機能を利用していること

当たり前のことばかりだと思いますが、ノービスな私にとっては、
カスタムエラーページの理解は、ゴチャゴチャしていたものでしたorz

ちゃんと理解すれば、私みたいにエラーなのに処理してくれない! なんか対応処理が2回起こった!
という状態にならなくて済みます。⊂⌒~⊃。Д。)⊃