.NET TIPS [ASP.NET MVC]例外フィルタをカスタマイズするには?[3.5、C#、VB]山田 祥寛2009/10/15 |
![]() |
「連載:ASP.NET MVC入門 第4回 フィルタ属性による認証/キャッシュ/セキュリティ対策の実装」では、フィルタ属性の1つであるHandleError属性を利用することで、カスタム・エラー・ページを有効化する方法について紹介した。サンプルという便宜上、取りあえずブラウザに直接、例外情報(例外の発生場所やエラー・メッセージ)を表示する例を紹介しているが、一般的にはエンド・ユーザーに例外情報を開示すべきケースは少ない(というよりも、開示すべきではない)。というのも、例外のようなアプリケーションの内部情報はエンド・ユーザーにとっては無意味なものであるのみならず、重要な情報を露出することから重大なセキュリティ・ホールの一因となってしまう可能性もあるためだ。
実際のアプリケーションでは、このような例外情報は背後でロギングし、エンド・ユーザーに対してはエラーが発生した旨と、場合によってはシステム管理者への連絡先を示すなど、ごくシンプルな情報を表示するにとどめるべきだろう。
そこで本稿では、例外発生時に例外情報をデータベースに登録するための、カスタムのフィルタ属性(例外フィルタ)であるErrorLog属性を定義してみよう。ErrorLog属性は、例外情報をロギングした後、自動的にビュー・スクリプトであるMyError.aspxファイルを検索&描画するので、(ファイル名は固定されるものの)標準的なHandleError属性と異なり、Web.Configの設定も不要である。
![]() |
本稿で作成するサンプル |
アクション・メソッドで例外が発生した場合に、指定されたエラー・ページが表示される。 |
![]() |
例外情報はErrorテーブルに記録される |
それではさっそく、具体的な実装の手順を見ていくことにしよう。
なお、本サンプル・プログラムを動作させるに当たっては、「連載:ASP.NET MVC入門 第1回 ASP.NET MVCフレームワーク 基本のキ」で紹介した手順に従って、ASP.NET MVCをインストールし、また、「ASP.NET MVC Web Application」プロジェクトを作成しておく必要がある。
1 .データベースを用意する
ここでは、アクション・メソッドで発生した例外情報をデータベースに登録するものとする。よって、サンプルを動作させるには、データベースに以下のようなErrorテーブルを用意し、Entity Data Model(エンティティ・データ・モデル。以下EDM)にもテーブルに対応したエンティティを追加しておく必要がある。EDMの作成方法については、「連載:ASP.NET MVC入門 第2回 スキャフォールディング機能で軽々DB連携アプリケーション」で解説しているので、参考にしていただきたい。
フィールド名 | データ型 | 概要 |
Id | INT | ログコード(主キー/自動連番) |
Uri | VARCHAR(255) | リクエストURI |
Controller | VARCHAR(30) | 例外が発生したコントローラの名前 |
Action | VARCHAR(30) | 例外が発生したアクションの名前 |
Stack | NVARCHAR(MAX) | スタック・トレース |
Updated | DATETIME | エラー発生日時 |
![]() |
||
Errorテーブルのフィールド・レイアウト |
2. 例外フィルタを定義する
次は本題、例外フィルタを表すErrorLogAttributeクラスを実装する。
|
||
ロギング機能付きの例外フィルタ(上:ErrorLogAttribute.cs、下:ErrorLogAttribute.vb) |
コードの大まかな流れはリスト内のコメントを参照いただくとして(Entity Frameworkに関する部分は、「特集:Visual Studio 2008 SP1新機能解説(2) .NETの新データアクセス・テクノロジ『ADO.NET Entity Framework』」を参考されたい)、ここでは例外フィルタにかかわるいくつかのポイントにフォーカスしてみよう。
例外フィルタはFilterAttibuteクラスを継承、IExceptionFilterインターフェイスを実装すること
FilterAttributeクラス(System.Web.Mvc名前空間)はフィルタ属性の基本的な機能を提供する基底クラス、IExceptionFilterインターフェイス(System.Web.Mvc名前空間)は例外フィルタに必要なメソッドを定義したインターフェイスである。例外フィルタを実装するには、これらのクラス/インターフェイスを継承/実装したクラスを定義する必要がある。
IExceptionFilterインターフェイスで実装しなければならないメソッドは、唯一、OnExceptionメソッドだけだ。OnExceptionメソッドはアクション・メソッドで例外が発生した場合に呼び出されるメソッドで、本稿の例のように、例外情報のロギングやカスタム・エラー・ページの呼び出しに利用することができる。
OnExceptionメソッドは引数としてExceptionContextオブジェクトを受け取る。例外情報をはじめ、例外の発生時に呼び出されていたコントローラ/アクションの情報、そのほか、ルート・パラメータなどには、すべてExceptionContextオブジェクトを介してアクセスが可能である。
例外が処理済みであることを通知する
例外フィルタ(OnExceptionメソッド)で例外を処理した場合には、例外が処理済みであることを明示的に通知する必要がある。これには、ExceptionContextオブジェクトのExceptionHandledプロパティにtrueをセットするだけでよい。
もしもExceptionHandledプロパティがfalse(デフォルト)である場合には、例外は未処理であると見なされ(例外が再スローされ)、この場合はそのまま標準のエラー・ページが表示されてしまうので、注意が必要だ。
処理後の結果を指定する
例外フィルタでの処理を終えた後、最終的な出力方法を決めるのはExceptionContextオブジェクトのResultプロパティの役割だ。
Resultプロパティには、ActionResult派生クラスのいずれかのインスタンスを設定することができる。ActionResult派生クラスについては、「連載:ASP.NET MVC入門 第3回 ActionResultオブジェクトでアクション操作も自由自在」を併せて参照していただくとよいだろう。
ここでは、ViewResultクラスをインスタンス化することで、強制的にビュー・スクリプトを呼び出しているわけだ。呼び出すビュー・スクリプトを設定するには、ViewNameプロパティを指定すればよい。ここでは「MyError」を呼び出しているので、Viewsフォルダ配下の、
(1)コントローラ名/MyError.aspx
(2)コントローラ名/MyError.ascx
(3)Shared/MyError.aspx
(4)Shared/MyError.ascx
が順に検索され、描画されることになる。ちなみに、例外情報をビュー変数経由で渡したいならば、ViewDataプロパティで設定することも可能だ。
3. アクション・メソッド&エラー・ページを用意する
例外フィルタが用意できたところで、実際に動作を確認してみよう。
ここでは、意図的に例外を発生するFilter/LogTestアクションと、例外発生時に呼び出されるMyError.aspxファイルを用意する。なお、MyError.aspxファイルは通常はアプリケーション共通で利用するのが一般的と思われることから、ここではViews/Sharedフォルダに配置するものとする。
|
||
意図的に例外を発生させるFilter/LogTestアクション(上:FilterController.cs、下:FilterController.vb) | ||
例外フィルタに固有の話ではないが、属性を宣言する場合には、クラス名の末尾のAttributeは省略可能である。つまり、ErrorLogAttributeであれば、単にErrorLogと記述できる。 |
|
|
カスタム・エラー・ページを表すビュー・スクリプト(Shared/MyError.aspx*) | |
* エラー・ページの内容はほとんど静的なコンテンツであるため、ここではC#版のコードのみを掲載する。 |
以上を理解したら、
http://localhost:8080/Filter/LogTest
のようなアドレスで、実際にサンプルを起動してみよう。冒頭の画面のように、カスタム・エラー・ページが表示され、かつ、Errorテーブルには例外情報が記録されていれば、ErrorLogフィルタは正しく動作している。
利用可能バージョン:.NET Framework 3.5 カテゴリ:ASP.NET MVC 処理対象:例外 使用ライブラリ:FilterAttributeクラス(System.Web.Mvc名前空間) 使用ライブラリ:IExceptionFilterインターフェイス(System.Web.Mvc名前空間) |
|
![]() |
「.NET TIPS」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
![]() |
|
|
|
![]() |