japan.internet.comThe Internet & IT Network
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2008年9月6日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
デベロッパー2007年1月9日 10:00

処理の例外への適切な対処法2:例外の詳細を開発者に通知する

海外海外internet.com発の記事
  • このエントリーを含むはてなブックマーク
  • この記事をクリップ!
  • Buzzurlにブックマーク
  • Yahoo!ブックマークに登録
  • newsing it!

はじめに

 ASP.NETアプリケーションで未処理の例外が発生すると、既定では訪問者に「ランタイムエラー」ページまたは例外の詳細ページが表示されます(どちらのページが表示されるかは、Webサイトの設定および訪問者がローカルホストから表示しているかどうかによります)。理想的なことを言えば、このような難解なエラーページは開発者だけに表示され、通常のユーザーにはユーザーフレンドリなカスタムエラーページが表示されるべきでしょう。前回の記事「未処理の例外への適切な対処法」では、未処理の例外への応答としてユーザーフレンドリなカスタムWebエラーページを表示するASP.NET Webアプリケーションの設定方法を紹介しました。

 ただし、前回の記事で紹介した方法では、未処理の例外が発生したときに内部的にResponse.Redirect()を使ってユーザーをカスタムエラーページにリダイレクトしています。ユーザーをリダイレクトすると、要求のコンテキストは失われます(リダイレクトによってブラウザがエラーページに新しい要求を送るからです)。そのため、ユーザーフレンドリなカスタムエラーページでは、発生したエラーについての情報を得ることができません。もっと詳しいエラーメッセージを表示するためには、こうした情報が必要になることもあります。

 未処理の例外がASP.NETランタイムに通知されると、アプリケーションレベルのErrorイベントがトリガされます。このイベントのためのイベントハンドラを作成することで、エラーの詳細にアクセスしたり、エラーを記録したり、開発者に通知したり、Server.Transfer()を使ってユーザーをカスタムエラーページに送ったりすることができます(コンテキストを維持して、カスタムエラーページから未処理の例外の詳細にアクセスできるようにします)。

 この記事では、Errorイベントのイベントハンドラを作成する方法を説明し、エラーの詳細を記録するためのフリーなオープンソースコンポーネントを紹介します。

Errorイベントを調べる

 HttpApplicationクラスは、すべてのASP.NET Webアプリケーションに共通のメソッド、プロパティ、イベントを表現するものです。このクラスのイベントの一つに、Errorイベントがあります。未処理の例外がASP.NETランタイムに通知されるたびに、このイベントがトリガされます。例えば、あるASP.NET Webページに、データベースに接続してDELETEステートメントを実行するコードがあるものとします。このページに訪問者があったときにデータベースがオフライン状態になっていると、SqlExceptionが発生します。コード内にエラー処理ロジックがなければ、この例外はASP.NETページの分離コードクラスからASP.NETランタイムに通知され、その時点でErrorイベントが発生します。

 未処理の例外が発生した場合、通常は次のいずれかを行います。

  • エンドユーザーにユーザーフレンドリなカスタムメッセージを表示する
  • そのエラーを「処理」する
  • この場合は、後で調査できるようにエラーを記録したり、電子メールを送ってエラーを開発者に通知したり、問題の「修正」を試みたりする必要があるかもしれません。

 エラーを「処理」するには、まずアプリケーションのErrorイベントのイベントハンドラを作成する必要があります。イベントハンドラは「Global.asax」で作成できます。あるいはHTTPモジュールで処理できます。イベントハンドラでは、Server.GetLastError()メソッドを使って未処理の例外の詳細を取得できます。エラーの詳細が得られたら、その情報を記録したり、開発者に通知したり、ユーザーフレンドリなカスタムエラーページに制御を渡したりできます。

Global.asaxでErrorイベントハンドラを作成する

 「Global.asax」は、Webアプリケーションのルートディレクトリに追加できるオプションのファイルで、このファイルを使用してアプリケーションレベルおよびセッションレベルのイベントを処理することができます。アプリケーションのErrorイベントのイベントハンドラを作成するには、まず「Global.asax」ファイルを自分のプロジェクトに追加します。ソリューションエクスプローラで目的のプロジェクトを右クリックし、[Add New Item]を選択し、ダイアログボックスから[Global Application Class]を選択します(図1のスクリーンショットを参照)。

図1
図1

 これにより、メインアプリケーションレベルのイベント(ErrorStartEnd)に関するイベントハンドラと、セッションレベルのイベント(StartEnd)に関するイベントハンドラを含むダミーの「Global.asax」ファイルが作成されます。いま問題にしているのはErrorイベントだけなので、残りのイベントハンドラは削除してかまいません。

 Errorイベントハンドラでは、次のメソッドを呼び出すことにより、発生した例外に関する情報にアクセスできます。

HttpContext.Current.Server.GetLastError()

 このメソッドから返されるExceptionオブジェクトには、ランタイムに通知されたエラー(そのErrorイベントをトリガしたもの)に関する情報が入っています。その例外がASP.NETページによるものであれば、元の例外がHttpUnhandledException内にラップされています。ASP.NETページレベルの例外には、後ほど紹介するInnerExceptionプロパティを通じてアクセスできます。

 未処理の例外が発生したときには、電子メールで開発者に例外の詳細を知らせると共に、前回の記事「未処理の例外への適切な対処法」で説明したように、ユーザーをカスタムエラーページにリダイレクトするものとしましょう。これを行うためには、「Web.config」内で<customErrors>を適切に設定し、それから「Global.asax」内のErrorイベントハンドラに次のコードを追加します。

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
  ’Get exception details

  Dim ex As Exception = HttpContext.Current.Server.GetLastError()

  If TypeOf ex Is HttpUnhandledException AndAlso _

    ex.InnerException IsNot Nothing Then
    ex = ex.InnerException
  End If

  If ex IsNot Nothing Then

    Try
      ’Email the administrator with information
      ’that an error has occurred
      ’!!! UPDATE THIS VALUE TO YOUR EMAIL ADDRESS
      Const ToAndFromAddress As String = "’email address’"

      ’(1) Create the MailMessage instance
      Dim mm As New System.Net.Mail.MailMessage(ToAndFromAddress, _
        ToAndFromAddress)

      ’(2) Assign the MailMessage’s properties
      mm.Subject = "An unhandled exception occurred!"

      mm.Body = String.Format( _
        "An unhandled exception occurred:{0}Message: {1}{0}{0} Stack Trace:{0}{2}", _
        System.Environment.NewLine, ex.Message, ex.StackTrace)
      mm.IsBodyHtml = False

      ’(3) Create the SmtpClient object
      Dim smtp As New System.Net.Mail.SmtpClient

      ’(4) Send the MailMessage (will use the Web.config settings)

      smtp.Send(mm)
    Catch
      ’Whoops, some problem sending email!
      ’Just send the user onto CustomErrorPage.aspx...
    End Try
  End If

End Sub

 イベントハンドラの最初の数行に特に注意を払ってください。発生した例外にアクセスし(HttpContext.Current.Server.GetLastError())、必要に応じてInnerExceptionプロパティを調べています。それから、「Sending Email in ASP.NET 2.0」に掲載したコードを使って、例外の詳細を指定の電子メールアドレスに送ります(このコードで使用しているSMTPリレーサーバーの詳細は「Web.config」にあります)。

 ユーザーがデータ駆動型のページを訪れ、データベースに接続する際に問題があったします。このとき、ユーザーには設定されているエラーページが表示されますが、開発者には例外の詳細を記した電子メールが送られます。

図2
図2

リダイレクトではなく制御をカスタムエラーページに移す

 前回の記事「未処理の例外への適切な対処法」で説明したように、「Web.config」の<customErrors>セクションの設定によって、未処理の例外が発生したときにユーザーフレンドリなカスタムエラーページを表示することができます。あいにく、ASP.NETランタイムは未処理の例外が発生したときにユーザーをカスタムエラーページに「リダイレクト」します。ランタイムが呼び出すResponse.Redirect(customErrorPageUrl)は、HTTPのステータスコード302をブラウザに送信するのですが、これは指定のURL(customErrorPageUrl)を要求せよという意味です。このリダイレクトは新たなWeb要求なので、未処理の例外を持っていた要求とは何の関連もありません。そのため、カスタムエラーページからServer.GetLastError()を呼び出すと、null値が返されます。

 しかし、カスタムエラーページでエラーに関する情報を保持したいこともあります。おそらく、発生したエラーに応じたメッセージを表示したり、特定の役割を持つ認証された訪問者に例外の詳細を表示したいことがあるでしょう。これはErrorイベントハンドラ内でのServer.Transfer(customErrorPageUrl)の呼び出しによって達成できます。ドキュメントによれば、Server.Transfer(url)は「現在のページの実行を終了し、指定されたURLパスを使って新しいページの実行を開始」します。要するに、現在の要求の実行がサーバー上の別のページに委ねられるのです。クライアントに明示的なリダイレクトメッセージが返されることはなく、すべてがサーバー側で行われます。

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
    ’... Email details of exception to developer ...

    Server.Transfer("~/SmartCustomErrorPage.aspx")
End Sub

 Server.Transfer()でコンテキストが維持されるので、カスタムエラーページではServer.GetLastError()を使って未処理の例外に関する情報を取得できます。ブラウザから見ると、コンテキストに変化はありません。つまり、ブラウザのアドレスバーには、Server.Transfer()された先のURLではなく、未処理の例外を発生させたページのURLが引き続き表示されるわけです。

 この記事のダウンロードサンプルを使用すると、もっと高度なカスタムエラーページ(SmartCustomErrorPage.aspx)を表示できます。このエラーページは例外の詳細を調べて、発生した例外のタイプに応じてメッセージを組み立てます。

HTTPモジュールでErrorイベントを処理する

 HTTPモジュールは、ASP.NETランタイムが発生させたイベントに応答できるマネージドコンポーネントです。代わりに、Errorイベントに応答するイベントハンドラをHTTPモジュール内に置くことができます。HTTPモジュールを使用することの利点は、HTTPモジュールアセンブリを「/bin」ディレクトリにドロップし、アプリケーションの「Web.config」に1行か2行の設定を追加するだけで既存のASP.NETアプリケーションに追加できる「プラグ可能な」コンポーネントを提供することにあります。

 エラー処理のためにHTTPモジュールを作成し設定するのは本稿の守備範囲を超えるので、ここで説明することはできません。代わりに、Atif Azizが提供しているフリーなオープンソースライブラリ、ELMAH(Error Logging Modules And Handlers)をお勧めします。ELMAHは、未処理の例外をデータストアに記録するためのHTTPモジュールと、例外の詳細をWebページまたはRSSフィードに表示するためのHTTPハンドラから成ります。

 ELMAHは、GotDotNet Workspaceからダウンロードできます。ELMAHのセットアップとインストールの詳細については、「Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components」を参照してください。ELMAHのセットアップに要する時間は60秒くらいです。これにより、例外の詳細な記録、開発者への充実した通知、および例外の詳細をオンラインで見られるユーザーフレンドリなWebページが提供されます。ぜひ試してください。

 この記事のダウンロードサンプルでは、ELMAHライブラリを使ってSQL Server 2005 Express Editionデータベースにエラーを記録します。

まとめ

 Webアプリケーションで未処理の例外が発生した場合、通常はエンドユーザーにユーザーフレンドリなカスタムエラーページが表示され、例外の詳細が「処理」されるようにしたいと思うでしょう。例外をどのように処理するかはアプリケーションごとに違ってくるでしょうが、通常は例外を記録し、開発者に通知します。前回の記事「未処理の例外への適切な対処法」では、カスタムエラーページの表示方法を説明し、今回の記事では、アプリケーションのErrorイベントのためのイベントハンドラの作成方法を説明しました。

 例外の記録と通知を行うシステムを独自に作成するよりも、フリーなオープンソースライブラリのELMAHを試してみるようお勧めします。ELMAHには、未処理の例外を記録するためのHTTPモジュールと、例外の詳細を電子メールで送るためのオプションが含まれています。

 それでは、ハッピープログラミング!

参考資料

著者紹介

Scott Mitchell(Scott Mitchell)
最新トップニュース
データメーション
【データメーション】
OSについて気に入らないこと(9月5日)
ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」
【ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」】
「導入期〜成長期へ!一歩一歩と前進を目指す『Annoii(アノイ)』」/maka hou,Inc.(9月5日)
最新テクノロジーの意外な処方箋
【最新テクノロジーの意外な処方箋】
グリッドコンピューティング技術でETに遭遇(9月5日)
Graphic Design Forum
【Graphic Design Forum】
古い Emigre を探して (9月3日)
エンジニアの独り言
【エンジニアの独り言】
データをローカルに保存するWebアプリケーション(8月22日)
デスマーチからの脱却
【デスマーチからの脱却】
30min. iPhoneアプリリリース(8月18日)
最新ハイテク講座
最新ハイテク講座
なぜ勝った? 世界No.1シェアをつかんだ“Windows”(9月5日)
developer.com
developer.com
デザインパターンの使い方: Composite(9月5日)
最新アフィリエイト事例にみる成功の法則
最新アフィリエイト事例にみる成功の法則
コンバージョンレートを高めよう!(9月5日)
百式のネットビジネス研究
百式のネットビジネス研究
ガジェット購入時に将来の買取保証プランを提供する「TechForward」(9月5日)
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(9月4日)
「IT の耳」
「IT の耳」
【書評】『検索にガンガンヒットさせる SEO の教科書』――SEO テクニックで効果的に PR する(9月4日)
検索エンジンマーケティング
検索エンジンマーケティング
果たしてモバイル SEO は必要なのか?(9月4日)
Eメールマーケティング事情
Eメールマーケティング事情
読者が迷惑メールと認識する時…(9月3日)
日本と韓国のインターネットビジネス最新動向調査
日本と韓国のインターネットビジネス最新動向調査
日本と韓国の動画サイト比較1―現状(9月3日)
SNSをビジネスに活用しよう
SNSをビジネスに活用しよう
「しまじろう」に学ぶ企業内コミュニティの活性化のポイント(9月2日)
海外のインターネットコムアメリカ韓国ドイツトルコ
Copyright 2008 Jupitermedia Corporation All Rights Reserved.http://www.internet.com/