在 ASP.NET 网站中记录未处理的异常
使用 MS Enterprise Application Blocks 在 ASP.NET 网站中记录未处理的异常。
引言
开发 ASP.NET 应用程序时,一项常规任务是规划未处理的异常。如果异常未被处理,默认情况下,ASP.NET 运行时会根据您配置网站的方式,向用户显示一个难看的错误消息,或者显示异常详细信息页面。允许用户看到难看的错误消息是极不推荐的(请参阅本文了解异常处理最佳实践)。如果您只是显示一个通用的异常详细信息页面,您将会丢失调试问题所需的宝贵信息。
几年来,我一直在我的网站中使用此策略来处理未处理的异常。当发生未处理的异常时,该策略是:
- 在应用程序级别的错误事件处理程序(*Global.asax*)中捕获错误。
- 通过发送包含异常详细信息的电子邮件来“处理”错误。
- 重定向到一个自定义网页,向最终用户显示一个用户友好的消息。
现在,我并不是建议您不应该在代码中使用 `try catch` 块来捕获可以恢复的错误。这是一种在单个中心位置捕获那些意外错误、记录异常信息、向开发人员发送电子邮件以及向用户显示友好消息的策略。
我过去使用的这种方法的问题在于,它将记录和发送电子邮件的任务留给了您自己手动实现。事实上,我只发送带有错误消息的电子邮件,并依赖服务器的应用程序日志来记录错误。仅凭电子邮件和应用程序日志,跟踪问题、用户是谁等等就变得非常困难。我希望能有一种更简单的方法来收到错误通知,并有一种方法来存储信息,以便我可以运行报告来查看错误,甚至查看一些统计数据。
于是,我开始研究 Microsoft Enterprise Application blocks,并认为它们正是我所需要的。本文尤其对我帮助很大,您可能希望为您的 N 层应用程序遵循这种方法。
我喜欢使用应用程序块的地方在于,您只需在 *web.config* 文件中输入一些设置,添加应用程序块的引用,然后只需几行代码,我就可以发送电子邮件并将异常记录到 SQL Server。接下来,再快速创建一个 Reporting Services 报告,我就可以轻松地在日志数据库中查看信息了!
使用代码
使用此代码需要什么
- MS Enterprise Library 5.0
- 必须使用至少 .NET Framework 3.5
- SQL Server - 并安装了 Enterprise Library 日志记录数据库
来自 MS Enterprise Library 文档
“在安装 Enterprise Library 的文件夹中,在 Windows 资源管理器中打开子文件夹 *Source\Blocks\Logging\Src\DatabaseTraceListener\Scripts*。此文件夹包含一个名为 *LoggingDatabase.sql* 的 SQL 脚本和一个名为 *CreateLoggingDb.cmd* 的命令文件,该文件执行此脚本。该脚本创建一个名为 Logging 的新数据库,并向其中添加数据库跟踪侦听器写入日志条目到数据库所需的所有表和存储过程。”
添加对以下应用程序块的引用(应位于 *C:\Program Files (x86)\Microsoft Enterprise Library 5.0\Bin\*)
- Microsoft.Practices.EnterpriseLibrary.Common.dll
- Microsoft.Practices.EnterpriseLibrary.Data.dll
- Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll
- Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.dll
- Microsoft.Practices.EnterpriseLibrary.Logging.dll
- Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll
安装 MS Enterprise Library 后,当您在 Visual Studio 中右键单击 *web.config* 文件时,您会看到一个菜单选项 *Edit Enterprise Library V5 Configuration*。您可以使用此工具输入必要的配置信息,或者通过手动更新 *web.config* 文件来完成。我强烈建议前者,尤其是如果您不熟悉使用应用程序块。就本文而言,在 *Blocks* 菜单下,选择 *Add Logging Settings* 和 *Add Exception Handling Settings*。默认情况下,您应该已经有了 *Application Settings* 和 *Database Settings*。添加这些设置后,您可以关闭并保存该工具,它将更新您的 *web.config* 文件。
为了简化,请使用此代码片段更新 *web.config*。然后您可以返回到工具以更轻松地查看设置。确保在 *Logging Settings* 中更新电子邮件地址和 STMP 服务器,并在 *Database Settings* 下更新日志数据库的连接字符串。
下面的代码片段已换行以避免页面滚动。
<configsections />
<section name="loggingConfiguration" requirepermission="true"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<section name="exceptionHandling" requirepermission="true"
type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
Configuration.ExceptionHandlingSettings,
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling,
Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
...
</configsections />
<loggingconfiguration tracingenabled="true"
defaultcategory="General" />
<listeners />
<add name="Email Trace Listener"
type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.
EmailTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging,
Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
listenerdatatype="Microsoft.Practices.EnterpriseLibrary.Logging.
Configuration.EmailTraceListenerData,
Microsoft.Practices.EnterpriseLibrary.Logging,
Version=5.0.414.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
toaddress="someone@yourcompany.com"
fromaddress="noreply@yourcompany.com"
subjectlineender="- Log Example Website"
smtpserver="YourSMTPServer"
formatter="Email Text Formatter"
traceoutputoptions="DateTime, Timestamp, ProcessId, Callstack" />
<add name="Database Trace Listener"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.
FormattedDatabaseTraceListener,
Microsoft.Practices.EnterpriseLibrary.Logging.Database,
Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
listenerdatatype="Microsoft.Practices.EnterpriseLibrary.Logging.
Database.Configuration.FormattedDatabaseTraceListenerData,
Microsoft.Practices.EnterpriseLibrary.Logging.Database,
Version=5.0.414.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
formatter="Text Formatter"
traceoutputoptions="LogicalOperationStack, DateTime,
Timestamp, ProcessId, ThreadId, Callstack"
databaseinstancename="LoggingConnectionString"
writelogstoredprocname="WriteLog"
addcategorystoredprocname="AddCategory" />
</listeners />
<formatters />
<add name="Text Formatter"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter,
Microsoft.Practices.EnterpriseLibrary.Logging,
Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
template="Application Name: Log Example Website
Message: {message}{newline}
Category: {category}{newline}
Extended Properties: {dictionary({key} - {value}{newline})}" />
<add name="Email Text Formatter"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35"
template="There was an error. Please see the Logging database
for more information. Timestamp: {timestamp(local)}
{newline} Message: {message}{newline}" />
</formatters />
<categorysources />
<add name="ErrorLogging" switchvalue="All" />
<listeners />
<add name="Email Trace Listener" />
<add name="Database Trace Listener" />
</listeners />
</add />
</categorysources />
<specialsources />
<allevents name="All Events" switchvalue="All" />
<notprocessed name="Unprocessed Category" switchvalue="All" />
<errors name="Logging Errors & Warnings" switchvalue="All" />
<listeners />
<add name="Email Trace Listener" />
<add name="Database Trace Listener" />
</listeners />
</errors />
</specialsources />
</loggingconfiguration />
<exceptionhandling />
<exceptionpolicies />
<add name="AllExceptionsPolicy" />
<exceptiontypes />
<add name="All Exceptions"
type="System.Exception, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
posthandlingaction="None" />
<exceptionhandlers />
<add title="Enterprise Library Exception Handling"
name="AllExceptionsLoggingHandler"
type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
Logging.LoggingExceptionHandler, Microsoft.Practices.
EnterpriseLibrary.ExceptionHandling.Logging,
Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
logcategory="ErrorLogging"
eventid="100" severity="Error"
formattertype="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
TextExceptionFormatter,
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
priority="0" />
</exceptionhandlers />
</add />
</exceptiontypes />
</add />
</exceptionpolicies />
</exceptionhandling />
<connectionstrings />
<add name="LoggingConnectionString"
connectionstring="Data Source=YourSQLServer;
Initial Catalog=Logging;
Integrated Security=SSPI"
providername="System.Data.SqlClient" />
</connectionstrings />
将此代码放入 *Global.asax* 文件中
protected void Application_Error(object sender, EventArgs e)
{
//uncomment in order to bypass logging when running locally.
//if (!Request.IsLocal)
//{
Exception ex = Server.GetLastError();
if (ex is HttpUnhandledException && ex.InnerException != null)
{
ex = ex.InnerException;
}
if (ex != null)
{
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.
ExceptionPolicy.HandleException(ex, "AllExceptionsPolicy");
Server.ClearError();
Response.Redirect("~/Utility/ErrorPage.htm");
}
//}
}
从上面的代码可以看出,在应用程序块处理完错误后,用户将被重定向到 *~/Utility/ErrorPage.htm* 页面。因此,您需要为您的站点创建一个页面,或者您可以使用本文下载示例代码中的页面。
就这样,这就是使用 MS Enterprise Application Blocks 在 ASP.NET 网站中处理未处理异常的全部内容。下载示例代码,其中包含一个用于演示如何处理未处理异常的项目。如果您熟悉 SQL Server Reporting Services,您可以创建自己的自定义报告来查看记录到 SQL Server 的数据。
最后,这是我的第一篇文章,非常感谢任何反馈。希望有人觉得它有用……谢谢!