未処理の例外を処理する (VB)
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
運用環境の Web アプリケーションでランタイム エラーが発生した場合は、開発者に通知し、後で診断できるようにエラーをログに記録することが重要です。 このチュートリアルでは、ASP.NET がランタイム エラーを処理する方法の概要を説明し、未処理の例外が ASP.NET ランタイムに到達するたびにカスタム コードを実行する 1 つの方法について説明します。
はじめに
ASP.NET アプリケーションで未処理の例外が発生すると、ASP.NET ランタイムにバブルアップされ、イベントが Error
発生し、適切なエラー ページが表示されます。 エラー ページには、3 つの異なる種類があります。ランタイム エラーの死の黄色い画面 (YSOD) です。例外の詳細 YSOD;およびカスタム エラー ページ。 前の チュートリアル では、リモート ユーザー用のカスタム エラー ページと、ローカルにアクセスするユーザーの例外の詳細 YSOD を使用するようにアプリケーションを構成しました。
サイトの外観に一致するわかりやすいカスタム エラー ページの使用は、既定のランタイム エラー YSOD より優先されますが、カスタム エラー ページの表示は、包括的なエラー処理ソリューションの一部にすぎません。 運用環境のアプリケーションでエラーが発生した場合、例外の原因を特定して対処できるように、開発者にエラーの通知を受け取る必要があります。 さらに、後でエラーを調べて診断できるように、エラーの詳細をログに記録する必要があります。
このチュートリアルでは、未処理の例外の詳細にアクセスして、ログに記録して開発者に通知できるようにする方法について説明します。 このチュートリアルに続く 2 つのチュートリアルでは、少し構成した後に、ランタイム エラーを開発者に自動的に通知し、その詳細をログに記録するエラー ログ ライブラリについて説明します。
注意
このチュートリアルで説明する情報は、未処理の例外を一意またはカスタマイズされた方法で処理する必要がある場合に最も役立ちます。 例外をログに記録して開発者に通知するだけで済む場合は、エラー ログ ライブラリを使用します。 次の 2 つのチュートリアルでは、このような 2 つのライブラリの概要について説明します。
イベントが発生したときにコードをError
実行する
イベントは、オブジェクトに、関心のあることが発生したことを通知し、別のオブジェクトが応答でコードを実行するためのメカニズムを提供します。 ASP.NET 開発者として、あなたはイベントの観点から考えることに慣れている。 訪問者が特定の Button をクリックしたときにコードを実行する場合は、その Button Click
のイベントのイベント ハンドラーを作成し、そこにコードを配置します。 ASP.NET ランタイムは、ハンドルされない例外が発生するたびにイベントを発生Error
させると、エラーの詳細をログに記録するためのコードがイベント ハンドラーに格納されます。 しかし、イベントのイベント ハンドラー Error
を作成するにはどうすればよいですか?
イベントはError
、要求の有効期間中に HttpApplication
HTTP パイプラインの特定のステージで発生する クラス内の多くのイベントの 1 つです。 たとえば、 HttpApplication
クラスの BeginRequest
イベント は、すべての要求の開始時に発生します。その AuthenticateRequest
イベント は、セキュリティ モジュールが要求者を識別したときに発生します。 これらのイベントにより、ページ開発者は HttpApplication
、要求の有効期間内のさまざまな時点でカスタム ロジックを実行する手段が得られます。
イベントのイベント ハンドラーは HttpApplication
、 という名前 Global.asax
の特別なファイルに配置できます。 Web サイトでこのファイルを作成するには、 という名前 Global.asax
のグローバル アプリケーション クラス テンプレートを使用して、Web サイトのルートに新しい項目を追加します。
図 1: Web アプリケーションに追加 Global.asax
する
(クリックするとフルサイズの画像が表示されます)
Visual Studio によって作成される Global.asax
ファイルの内容と構造は、Web アプリケーション プロジェクト (WAP) と Web サイト プロジェクト (WSP) のどちらを使用しているかによって若干異なります。 WAP では、 Global.asax
は 2 つの別個のファイルとして実装されます。 Global.asax
Global.asax.vb
ファイルにはGlobal.asax
、ファイルを参照.vb
する@Application
ディレクティブ以外に何も含めず、対象のイベント ハンドラーはファイルでGlobal.asax.vb
定義されます。 WSP の場合、1 つのファイル () のみが作成され、 Global.asax
イベント ハンドラーは ブロックで <script runat="server">
定義されます。
Global.asax
Visual Studio のグローバル アプリケーション クラス テンプレートによって WAP で作成されたファイルには、および Application_Error
という名前Application_BeginRequest
Application_AuthenticateRequest
のイベント ハンドラーが含まれています。これは、それぞれ イベント 、AuthenticateRequest
、および Error
のHttpApplication
イベント BeginRequest
ハンドラーです。 、および Session_End
という名前Application_End
Application_Start
Session_Start
のイベント ハンドラーもあります。これは、Web アプリケーションの起動時、新しいセッションの開始時、アプリケーションの終了時、およびセッションの終了時に発生するイベント ハンドラーです。 Global.asax
Visual Studio によって WSP で作成されたファイルには、、Application_Start
、Session_Start
、Application_End
および Session_End
イベント ハンドラーだけがApplication_Error
含まれています。
注意
ASP.NET アプリケーションをデプロイするときは、そのファイルを Global.asax
運用環境にコピーする必要があります。 WAP で作成されたファイルは Global.asax.vb
、このコードがプロジェクトのアセンブリにコンパイルされるため、運用環境にコピーする必要はありません。
Visual Studio のグローバル アプリケーション クラス テンプレートによって作成されたイベント ハンドラーは、すべてではありません。 イベント ハンドラー に という名前を付けることで、任意 HttpApplication
のイベントのイベント ハンドラー Application_EventName
を追加できます。 たとえば、次のコードをファイルに追加して、Global.asax
イベントのイベント ハンドラーをAuthorizeRequest
作成できます。
Sub Application_AuthorizeRequest(ByVal sender As Object, ByVal e As EventArgs)
' Event handler code
End Sub
同様に、グローバル アプリケーション クラス テンプレートによって作成された、不要なイベント ハンドラーを削除することもできます。 このチュートリアルでは、イベントのイベント ハンドラー Error
のみが必要です。ファイルから他のイベント ハンドラーを自由に Global.asax
削除できます。
注意
HTTP モジュールは、イベントの イベント ハンドラーを定義する別の方法を HttpApplication
提供します。 HTTP モジュールは、Web アプリケーション プロジェクト内に直接配置したり、別のクラス ライブラリに分離したりできるクラス ファイルとして作成されます。 これらはクラス ライブラリに分離できるため、HTTP モジュールは、イベント ハンドラーを作成するためのより柔軟で再利用可能なモデルを HttpApplication
提供します。 Global.asax
ファイルは、それが存在する Web アプリケーションに固有ですが、HTTP モジュールはアセンブリにコンパイルできます。その時点で、HTTP モジュールを Web サイトに追加することは、アセンブリを フォルダーにBin
ドロップして にモジュールWeb.config
を登録するのと同じくらい簡単です。 このチュートリアルでは、HTTP モジュールの作成と使用については説明しませんが、次の 2 つのチュートリアルで使用される 2 つのエラー ログ ライブラリは HTTP モジュールとして実装されています。 HTTP モジュールの利点の詳細については、「HTTP モジュールとハンドラーを使用してプラグ可能な ASP.NET コンポーネントを作成する」を参照してください。
未処理の例外に関する情報の取得
この時点で、イベント ハンドラーを含む Global.asax ファイルがあります Application_Error
。 このイベント ハンドラーを実行するときは、開発者にエラーを通知し、その詳細をログに記録する必要があります。 これらのタスクを実行するには、まず、発生した例外の詳細を確認する必要があります。 Server オブジェクトの GetLastError
メソッド を使用して、イベントが発生する原因となった未処理の例外の詳細を Error
取得します。
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Get the error details
Dim lastErrorWrapper As HttpException = _
CType(Server.GetLastError(), HttpException)
End Sub
メソッドはGetLastError
、 型Exception
のオブジェクトを返します。これは、.NET Framework内のすべての例外の基本型です。 しかし、上記のコードでは、 によって GetLastError
返された Exception オブジェクトを オブジェクトに HttpException
キャストしています。 ASP.NET リソースの Error
処理中に例外がスローされたためにイベントが発生する場合、スローされた例外は 内で HttpException
ラップされます。 Error イベントを発生させた実際の例外を取得するには、 プロパティを InnerException
使用します。 存在しないページの Error
要求など、HTTP ベースの例外が原因でイベントが発生した場合は、 HttpException
がスローされますが、内部例外はありません。
次のコードでは、 をGetLastErrormessage
使用して、イベントをトリガーした例外に関する情報をError
取得し、 という名前lastErrorWrapper
の変数に をHttpException
格納します。 次に、発生元の例外の型、メッセージ、スタック トレースを 3 つの文字列変数に格納し、 がイベントをトリガーしたError
実際の例外 (HTTP ベースの例外の場合) か、または要求の処理中にスローされた例外のラッパーであるかどうかを確認lastErrorWrapper
します。
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Get the error details
Dim lastErrorWrapper As HttpException = _
CType(Server.GetLastError(), HttpException)
Dim lastError As Exception = lastErrorWrapper
If lastErrorWrapper.InnerException IsNot Nothing Then
lastError = lastErrorWrapper.InnerException
End If
Dim lastErrorTypeName As String = lastError.GetType().ToString()
Dim lastErrorMessage As String = lastError.Message
Dim lastErrorStackTrace As String = lastError.StackTrace
End Sub
この時点で、例外の詳細をデータベース テーブルに記録するコードを記述するために必要なすべての情報があります。 目的のエラーの詳細 (型、メッセージ、スタック トレースなど) ごとに列を含むデータベース テーブルを作成し、要求されたページの URL や現在ログオンしているユーザーの名前などの便利な情報を作成できます。 Application_Error
イベント ハンドラーでは、データベースに接続し、テーブルにレコードを挿入します。 同様に、電子メールでエラーを開発者に警告するコードを追加することもできます。
次の 2 つのチュートリアルで確認したエラー ログ ライブラリは、このような機能をすぐに使用できるため、このエラー ログと通知を自分で作成する必要はありません。 ただし、イベントが Error
発生していること、およびイベント ハンドラーを使用してエラーの Application_Error
詳細をログに記録し、開発者に通知できることを示すために、エラーが発生したときに開発者に通知するコードを追加しましょう。
未処理の例外が発生したときに開発者に通知する
運用環境で未処理の例外が発生した場合は、エラーを評価し、実行する必要があるアクションを決定できるように、開発チームに警告することが重要です。 たとえば、データベースへの接続でエラーが発生した場合は、接続文字列チェック倍にする必要があります。また、Web ホスティング会社でサポート チケットを開く必要があります。 プログラミング エラーが原因で例外が発生した場合は、将来このようなエラーを防ぐために、追加のコードまたは検証ロジックを追加する必要があります。
名前空間の .NET Framework クラスをSystem.Net.Mail
使用すると、電子メールを簡単に送信できます。 クラスはMailMessage
電子メール メッセージを表し、 などのTo
Body
From
Subject
プロパティがあります。Attachments
SmtpClass
は、指定した SMTP サーバーをMailMessage
使用してオブジェクトを送信するために使用されます。SMTP サーバーの設定は、 の Web.config file
要素で<system.net>
プログラムまたは宣言によって指定できます。 ASP.NET アプリケーションで電子メール メッセージを送信する方法の詳細については、「ASP.NET Web ページ サイトからEmailを送信する」および「System.Net.Mail FAQ」をチェック。
注意
要素 <system.net>
には、電子メールの送信時に SmtpClient
クラスによって使用される SMTP サーバー設定が含まれます。 Web ホスティング会社には、アプリケーションからメールを送信するために使用できる SMTP サーバーがある可能性があります。 Web アプリケーションで使用する必要がある SMTP サーバー設定については、Web ホストのサポート セクションを参照してください。
次のコードをイベント ハンドラーに Application_Error
追加して、エラーが発生したときに開発者に電子メールを送信します。
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Get the error details
Dim lastErrorWrapper As HttpException = _
CType(Server.GetLastError(), HttpException)
Dim lastError As Exception = lastErrorWrapper
If lastErrorWrapper.InnerException IsNot Nothing Then
lastError = lastErrorWrapper.InnerException
End If
Dim lastErrorTypeName As String = lastError.GetType().ToString()
Dim lastErrorMessage As String = lastError.Message
Dim lastErrorStackTrace As String = lastError.StackTrace
Const ToAddress As String = "support@example.com"
Const FromAddress As String = "support@example.com"
Const Subject As String = "An Error Has Occurred!"
' Create the MailMessage object
Dim mm As New MailMessage(FromAddress, ToAddress)
mm.Subject = Subject
mm.IsBodyHtml = True
mm.Priority = MailPriority.High
mm.Body = string.Format( _
"<html>" & vbCrLf & _
" <body>" & vbCrLf & _
" <h1>An Error Has Occurred!</h1>" & vbCrLf & _
" <table cellpadding=""5"" cellspacing=""0"" border=""1"">" & vbCrLf & _
" <tr>" & vbCrLf & _
" <tdtext-align: right;font-weight: bold"">URL:</td>" & vbCrLf & _
" <td>{0}</td>" & vbCrLf & _
" </tr>" & vbCrLf & _
" <tr>" & vbCrLf & _
" <tdtext-align: right;font-weight: bold"">User:</td>" & vbCrLf & _
" <td>{1}</td>" & vbCrLf & _
" </tr>" & vbCrLf & _
" <tr>" & vbCrLf & _
" <tdtext-align: right;font-weight: bold"">Exception Type:</td>" & vbCrLf & _
" <td>{2}</td>" & vbCrLf & _
" </tr>" & vbCrLf & _
" <tr>" & vbCrLf & _
" <tdtext-align: right;font-weight: bold"">Message:</td>" & vbCrLf & _
" <td>{3}</td>" & vbCrLf & _
" </tr>" & vbCrLf & _
" <tr>" & vbCrLf & _
" <tdtext-align: right;font-weight: bold"">Stack Trace:</td>" & vbCrLf & _
" <td>{4}</td>" & vbCrLf & _
" </tr> " & vbCrLf & _
" </table>" & vbCrLf & _
" </body>" & vbCrLf & _
"</html>", _
Request.RawUrl, _
User.Identity.Name, _
lastErrorTypeName, _
lastErrorMessage, _
lastErrorStackTrace.Replace(Environment.NewLine, "<br />"))
'Attach the Yellow Screen of Death for this error
Dim YSODmarkup As String = lastErrorWrapper.GetHtmlErrorMessage()
If Not String.IsNullOrEmpty(YSODmarkup) Then
Dim YSOD As Attachment = _
Attachment.CreateAttachmentFromString(YSODmarkup, "YSOD.htm")
mm.Attachments.Add(YSOD)
End If
' Send the email
Dim smtp As New SmtpClient()
smtp.Send(mm)
End Sub
上記のコードは非常に長い間、その大部分は開発者に送信された電子メールに表示される HTML を作成します。 コードは、メソッド (lastErrorWrapper
) によって返される をGetLastError
HttpException
参照することから始まります。 要求によって発生した実際の例外は を介して lastErrorWrapper.InnerException
取得され、変数 lastError
に割り当てられます。 型、メッセージ、およびスタック トレース情報は、 から lastError
取得され、3 つの文字列変数に格納されます。
次に、 という名前mm
のMailMessage
オブジェクトが作成されます。 電子メール本文は HTML 形式で、要求されたページの URL、現在ログオンしているユーザーの名前、例外に関する情報 (型、メッセージ、スタック トレース) が表示されます。 クラスの良い点 HttpException
の 1 つは、 GetHtmlErrorMessage メソッドを呼び出すことで、例外の詳細の黄色い画面 (YSOD) の作成に使用される HTML を生成できることです。 このメソッドは、例外の詳細 YSOD マークアップを取得し、添付ファイルとして電子メールに追加するために使用されます。 注意が必要です。イベントをトリガーした Error
例外が HTTP ベースの例外 (存在しないページの要求など) GetHtmlErrorMessage
である場合、メソッドは を返 null
します。
最後の手順では、 を送信します MailMessage
。 これを行うには、新しい SmtpClient
メソッドを作成し、そのメソッドを Send
呼び出します。
注意
Web アプリケーションでこのコードを使用する前に、 定数と 定数のToAddress
値を、support@example.comエラー通知メールの送信先とFromAddress
送信元のメール アドレスに変更する必要があります。 また、 の セクションWeb.config
で SMTP サーバー設定を<system.net>
指定する必要があります。 使用する SMTP サーバーの設定を決定するには、Web ホスト プロバイダーに問い合わせてください。
このコードを配置すると、エラーが発生するたびに、開発者はエラーを要約し、YSOD を含む電子メール メッセージを送信します。 前のチュートリアルでは、Genre.aspxにアクセスし、 などのGenre.aspx?ID=foo
クエリ文字列を使用して無効なID
値を渡すことで、ランタイム エラーを示しました。 ファイルが配置されたページにアクセスすると、前のチュートリアルと Global.asax
同じユーザー エクスペリエンスが生成されます。開発環境では、引き続き例外の詳細の黄色い画面が表示されますが、運用環境ではカスタム エラー ページが表示されます。 この既存の動作に加えて、開発者には電子メールが送信されます。
図 2 は、 にアクセスしたときに受信したメールを Genre.aspx?ID=foo
示しています。 電子メール本文は例外情報を要約し YSOD.htm
、添付ファイルには例外の詳細 YSOD に表示されるコンテンツが表示されます ( 図 3 を参照)。
図 2: 未処理の例外が発生するたびに、開発者にEmail通知が送信される
(クリックするとフルサイズの画像が表示されます)
図 3: Email通知には、例外の詳細 YSOD が添付ファイルとして含まれています
(クリックするとフルサイズの画像が表示されます)
カスタム エラー ページの使用について
このチュートリアルでは、 と イベント ハンドラーをApplication_Error
使用Global.asax
して、ハンドルされない例外が発生したときにコードを実行する方法について説明しました。 具体的には、このイベント ハンドラーを使用して、開発者にエラーを通知しました。それを拡張して、エラーの詳細をデータベースに記録することもできます。 イベント ハンドラーが Application_Error
存在しても、エンド ユーザーのエクスペリエンスには影響しません。 エラーの詳細 YSOD、ランタイム エラー YSOD、カスタム エラー ページなど、構成済みのエラー ページが引き続き表示されます。
カスタム エラー ページを使用するときに、ファイルとApplication_Error
イベントが必要かどうかGlobal.asax
疑問に思うのが自然です。 エラーが発生すると、ユーザーにカスタム エラー ページが表示されるため、開発者に通知するコードを配置し、エラーの詳細をカスタム エラー ページの分離コード クラスに記録できないのはなぜですか? カスタム エラー ページの分離コード クラスにコードを追加することはできますが、前のチュートリアルで説明した手法を使用するときにイベントをトリガーした Error
例外の詳細にはアクセスできません。 GetLastError
カスタム エラー ページから メソッドを呼び出すと、 が返されますNothing
。
この動作の理由は、カスタム エラー ページにリダイレクトによって到達するためです。 ハンドルされない例外が ASP.NET ランタイムに達すると、ASP.NET エンジンはそのError
イベント (イベント ハンドラーをApplication_Error
実行) を発生させ、 を発行Response.Redirect(customErrorPageUrl)
してユーザーをカスタム エラー ページにリダイレクトします。 メソッドは Response.Redirect
HTTP 302 状態コードを使用してクライアントに応答を送信し、新しい URL (カスタム エラー ページ) を要求するようにブラウザーに指示します。 その後、ブラウザーはこの新しいページを自動的に要求します。 ブラウザーのアドレス バーがカスタム エラー ページ URL に変わるため、エラーが発生したページとは別にカスタム エラー ページが要求されたことを確認できます ( 図 4 を参照)。
図 4: エラーが発生すると、ブラウザーはカスタム エラー ページ URL にリダイレクトされます
(クリックするとフルサイズの画像が表示されます)
最終的な効果は、サーバーが HTTP 302 リダイレクトで応答したときに、ハンドルされない例外が発生した要求が終了することです。 カスタム エラー ページに対する後続の要求は、まったく新しい要求です。この時点で、ASP.NET エンジンはエラー情報を破棄し、さらに、前の要求の未処理の例外をカスタム エラー ページの新しい要求に関連付ける方法はありません。 これが、カスタム エラー ページから呼び出されたときに を返すnull
理由GetLastError
です。
ただし、エラーの原因となったのと同じ要求中にカスタム エラー ページを実行することもできます。 メソッドは Server.Transfer(url)
、指定した URL に実行を転送し、同じ要求内で処理します。 イベント ハンドラー内のコードを Application_Error
カスタム エラー ページの分離コード クラスに移動し、 を次のコードに Global.asax
置き換えます。
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Get the error details
Dim lastErrorWrapper As HttpException = _
CType(Server.GetLastError(), HttpException)
If lastErrorWrapper.GetHttpCode() = 404 Then
Server.Transfer("~/ErrorPages/404.aspx")
Else
Server.Transfer("~/ErrorPages/Oops.aspx")
End If
End Sub
ハンドルされない例外が発生すると、 Application_Error
イベント ハンドラーは HTTP 状態コードに基づいて適切なカスタム エラー ページに制御を転送します。 制御が転送されたため、カスタム エラー ページは を介して Server.GetLastError
未処理の例外情報にアクセスでき、開発者にエラーを通知してその詳細をログに記録できます。 この呼び出しにより Server.Transfer
、ASP.NET エンジンがユーザーをカスタム エラー ページにリダイレクトできなくなります。 代わりに、カスタム エラー ページのコンテンツが、エラーを生成したページへの応答として返されます。
まとめ
ASP.NET Web アプリケーションでハンドルされない例外が発生すると、ASP.NET ランタイムによってイベントが Error
発生し、構成されたエラー ページが表示されます。 Error イベントのイベント ハンドラーを作成することで、開発者にエラーを通知したり、詳細をログに記録したり、他の方法で処理したりできます。 イベントのイベント ハンドラー HttpApplication
Error
を作成するには、次の 2 つの方法があります。ファイル内 Global.asax
または HTTP モジュールから。 このチュートリアルでは、電子メール メッセージを Error
使用して開発者にエラーを Global.asax
通知するイベント ハンドラーをファイルに作成する方法について説明しました。
イベント ハンドラーの Error
作成は、一意またはカスタマイズされた方法で未処理の例外を処理する必要がある場合に便利です。 ただし、例外をログに記録したり、開発者に通知したりするために独自 Error
のイベント ハンドラーを作成することは、数分でセットアップできる無料で使いやすいエラー ログ ライブラリが既に存在するため、時間の最も効率的な使用ではありません。 次の 2 つのチュートリアルでは、このような 2 つのライブラリを調べます。
プログラミングに満足!
もっと読む
このチュートリアルで説明するトピックの詳細については、次のリソースを参照してください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示