エラー ハンドラの完全なコード例
更新 : 2007 年 11 月
このコード例には、ページレベルとアプリケーションレベルの両方の例外処理に関する要素が含まれます。
コード例のファイル
このコード例のファイルは次のとおりです。
Web.config
Global.asax
Default.aspx
ExceptionUtility (App_Code フォルダに配置します)
GenericErrorPage.aspx
HttpErrorPage.aspx
Web.config
Web.config ファイルの例を次に示します。customErrors の初期設定では、未処理のエラーは HttpErrorPage.aspx ファイルに送られます。
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true" />
<!-- Turn on Custom Errors -->
<customErrors
mode="RemoteOnly"
defaultRedirect="HttpErrorPage.aspx">
</customErrors >
</system.web>
</configuration>
Global.asax
Global.asax ファイルの例を次に示します。Global.asax ファイルでエラー イベント ハンドラを有効にするには、Web.config ファイルの変更が必要です。構成ファイルが優先されます。そのため、customErrors を Off に設定するか、defaultRedirect 設定を削除します。Web.config 構成ファイルに、Off に設定された customErrors がある場合、Global.asax の Application_Error イベント ハンドラがすべての未処理エラーを処理します。
セキュリティに関するメモ : |
---|
Global.asax ファイルに Application_Error ハンドラがない場合、Web.config ファイルの customErrors を Off に設定しないでください。Web サイトに関する情報が、サイトにエラーを発生させるようなユーザーに公開される危険性があります。 |
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
// Give the user some information, but
// stay on the default page
Exception exc = Server.GetLastError();
Response.Write("<h2>Global Page Error</h2>\n");
Response.Write(
"<p>" + exc.Message + "</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");
// Log the exception and notify system operators
ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);
// Clear the error from the server
Server.ClearError();
}
ExceptionUtility
ExceptionUtility ファイルの例を次に示します。エラー ログはコンピュータの ErrorLog ファイルに送信されます。または、コンピュータが Web ファームの一部の場合、エラー ログは、グローバルに使用できるテキスト ファイルまたはデータベースに記録されることがあります。また、場合によっては、システム管理者に問題について迅速に通知する必要があります。次の ExceptionUtility には静的メソッドが 2 つあります。1 つは例外をログに記録するメソッドで、もう 1 つはシステム管理者に通知するメソッドです。これらのメソッドをコードに実装する方法は、組織の要件によって変わります。たとえば、アプリケーションがエラー ログを出力できるようにするには、App_Data フォルダに NETWORK SERVICE の書き込みアクセス許可を付与する必要があります。
using System;
using System.IO;
using System.Web;
// Create our own utility for exceptions
public sealed class ExceptionUtility
{
// All methods are static, so this can be private
private ExceptionUtility()
{ }
// Log an Exception
public static void LogException(Exception exc, string source)
{
// Include enterprise logic for logging exceptions
// Get the absolute path to the log file
string logFile = "App_Data/ErrorLog.txt";
logFile = HttpContext.Current.Server.MapPath(logFile);
// Open the log file for append and write the log
StreamWriter sw = new StreamWriter(logFile, true);
sw.Write("******************** " + DateTime.Now);
sw.WriteLine(" ********************");
if (exc.InnerException != null)
{
sw.Write("Inner Exception Type: ");
sw.WriteLine(exc.InnerException.GetType().ToString());
sw.Write("Inner Exception: ");
sw.WriteLine(exc.InnerException.Message);
sw.Write("Inner Source: ");
sw.WriteLine(exc.InnerException.Source);
if (exc.InnerException.StackTrace != null)
sw.WriteLine("Inner Stack Trace: ");
sw.WriteLine(exc.InnerException.StackTrace);
}
sw.Write("Exception Type: ");
sw.WriteLine(exc.GetType().ToString());
sw.WriteLine("Exception: " + exc.Message);
sw.WriteLine("Source: " + source);
sw.WriteLine("Stack Trace: ");
if (exc.StackTrace != null)
sw.WriteLine(exc.StackTrace);
sw.WriteLine();
sw.Close();
}
// Notify System Operators about an exception
public static void NotifySystemOps(Exception exc)
{
// Include code for notifying IT system operators
}
}
Default.aspx
Default.aspx ページの例を次に示します。このファイルには 3 つのボタンがあり、それぞれ異なる例外を発生させます。このページの Page_Error ハンドラは特定のエラーをフィルタ処理し、3 つの個別の方法で 3 つの例外を処理します。また、存在しないファイルへのリンクもあります。これは、ページで処理されない 4 種類目のエラーです。
<%@ Page Language="C#" %>
<script runat="server">
protected void Submit_Click(object sender, EventArgs e)
{
string arg = ((Button)sender).CommandArgument;
if (arg.Equals("1"))
{
// Exception handled on the Generic Error Page
throw new InvalidOperationException("Invalid click operation?!");
}
else if (arg.Equals("2"))
{
// Exception handled on the current page
throw new ArgumentOutOfRangeException("click?!");
}
else
{
// Exception handled on the Http Error Page (per Web.Config)
throw new Exception("Generic click problem?!");
}
}
private void Page_Error(object sender, EventArgs e)
{
// Get last error from the server
Exception exc = Server.GetLastError();
// Filter for a specific kind of exception
if (exc is ArgumentOutOfRangeException)
{
// Give the user some information, but
// stay on the default page
Response.Write("<h2>Default Page Error</h2>\n");
Response.Write(
"<p>ArgumentOutOfRange: Your click must have " +
"been out of range?!</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");
// Log the exception and notify system operators
ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);
// Clear the error from the server
Server.ClearError();
}
// Filter for other kinds of exceptions
else if (exc is InvalidOperationException)
{
// Pass the error on to the Generic Error page
Server.Transfer("GenericErrorPage.aspx", true);
}
else
{
// Pass the error on to the default global handler
}
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Exception Handler Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>Default Page</h2>
<p>
Click this button to create a InvalidOperationException.<br />
<asp:Button ID="Submit1" runat="server" CommandArgument="1"
OnClick="Submit_Click" Text="Click 1" />
</p>
<p>
Click this button to create a ArgumentOutOfRangeException.<br />
<asp:Button ID="Submit2" runat="server" CommandArgument="2"
OnClick="Submit_Click" Text="Click 2" />
</p>
<p>
Click this button to create a generic Exception.<br />
<asp:Button ID="Submit3" runat="server" CommandArgument="3"
OnClick="Submit_Click" Text="Click 3" />
</p>
<p>Click this link to attempt to access a non-existent page:<br />
<a href="NoPage.aspx">NoPage.aspx</a>
</p>
</div>
</form>
</body>
</html>
GenericErrorPage.aspx
GenericErrorPage.aspx ページの例を次に示します。このページは、リモート ユーザーに表示する安全なメッセージを作成します。ローカル ユーザー (アプリケーションの開発者とテスト担当者) 向けに、完成した例外レポートを表示します。
<%@ Page Language="C#" %>
<script runat="server">
protected Exception ex = null;
protected void Page_Load(object sender, EventArgs e)
{
// Get the last error from the server
Exception ex = Server.GetLastError();
// Create a safe message
string safeMsg = "A problem has occurred in the web site. ";
// Show Inner Exception fields for local access
if (ex.InnerException != null)
{
innerTrace.Text = ex.InnerException.StackTrace;
InnerErrorPanel.Visible = Request.IsLocal;
innerMessage.Text = ex.InnerException.Message;
}
// Show Trace for local access
if (Request.IsLocal)
exTrace.Visible = true;
else
ex = new Exception(safeMsg, ex);
// Fill the page fields
exMessage.Text = ex.Message;
exTrace.Text = ex.StackTrace;
// Log the exception and notify system operators
ExceptionUtility.LogException(ex, "Generic Error Page");
ExceptionUtility.NotifySystemOps(ex);
// Clear the error from the server
Server.ClearError();
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Generic Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>Generic Error Page</h2>
<asp:Panel ID="InnerErrorPanel" runat="server" Visible="false">
<p>
Inner Error Message:<br />
<asp:Label ID="innerMessage" runat="server"
Font-Bold="true" Font-Size="Large" /><br />
</p>
<pre>
<asp:Label ID="innerTrace" runat="server" />
</pre>
</asp:Panel>
<p>
Error Message:<br />
<asp:Label ID="exMessage" runat="server"
Font-Bold="true" Font-Size="Large" />
</p>
<pre>
<asp:Label ID="exTrace" runat="server" visible="false" />
</pre>
</div>
</form>
</body>
</html>
HttpErrorPage.aspx
HttpErrorPage.aspx ページの例を次に示します。また、このページでは、エラー コード値によって変わる安全なメッセージを作成します。このメッセージはリモート ユーザーに表示されます。ローカル ユーザーの場合、ページには完成した例外レポートが表示されます。
<%@ Page Language="C#" %>
<script runat="server">
protected HttpException ex = null;
protected void Page_Load(object sender, EventArgs e)
{
ex = (HttpException)Server.GetLastError();
string safeMsg = String.Empty;
// Filter for Error Codes and set text
if (ex.ErrorCode >= 400 && ex.ErrorCode < 500)
{
ex = new HttpException
(ex.ErrorCode,
"Your file could not be found or " +
"there was an access problem.", ex);
}
else if (ex.ErrorCode > 499)
ex = new HttpException
(ex.ErrorCode,
"There was an error on the server.", ex);
else
ex = new HttpException
(ex.ErrorCode,
"There was a problem " +
"with the web site.", ex);
// Log the exception and notify system operators
ExceptionUtility.LogException(ex, "HttpErrorPage");
ExceptionUtility.NotifySystemOps(ex);
// Fill the page fields
exMessage.Text = ex.Message;
exTrace.Text = ex.StackTrace;
// Show Inner Exception fields for local access
if (ex.InnerException != null)
{
innerTrace.Text = ex.InnerException.StackTrace;
InnerErrorPanel.Visible = Request.IsLocal;
innerMessage.Text = ex.InnerException.Message;
}
// Show Trace for local access
exTrace.Visible = Request.IsLocal;
// Clear the error from the server
Server.ClearError();
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Generic Error Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>Http Error Page</h2>
<asp:Panel ID="InnerErrorPanel" runat="server" Visible="false">
<asp:Label ID="innerMessage" runat="server"
Font-Bold="true" Font-Size="Large" /><br />
<pre>
<asp:Label ID="innerTrace" runat="server" />
</pre>
</asp:Panel>
Error Message:<br />
<asp:Label ID="exMessage" runat="server"
Font-Bold="true" Font-Size="Large" />
<pre>
<asp:Label ID="exTrace" runat="server" visible="false" />
</pre>
</div>
</form>
</body>
</html>