[原创]在ASP.NET项目中建立统一的异常处理机制
原创文章,转载请注明:http://www.cnblogs.com/zzdong168
1简介
异常处理是常见的程序开发任务,程序能够统一处理在执行期间发生的异常,是建立稳定程序的关键措施之一.
.NET公共语言运行库提供了一个模型,以统一的方式通知程序发生的错误,从而为设计容错软件提供了极大的帮助.所有的.NET Framework操作都通过引发异常来指示出现错误.异常从发生问题的代码区域引发,然后沿堆栈向上传递,直到应用程序处理它或程序终止.
2运行库如何管理异常
公共语言运行库位每个可执行文件创建一个异常信息表. 在异常信息表中,可执行文件的每个方法都有一个关联的异常处理信息数组(可以为空)。数组中的每一项描述一个受保护的代码块、任何与该代码关联的异常筛选器和任何异常处理程序(Catch 语句)。此异常表非常有效,在没有发生异常时,在处理器时间或内存使用上没有性能损失。仅在异常发生时使用资源。(如上图)
异常发生时,公共语言运行库开始执行如上图中的步骤进行异常的捕获和处理:
(1) Function2中发生异常,运行库在该方法关联的异常信息数组中搜索满足条件的异常处理项.
a) 当前执行指令在受保护的代码块描述范围内
b) 包含异常处理程序或包含处理异常的筛选器
如果存在满足条件的异常处理信息项,则调用对应的异常处理程序.
(2) Function2没有满足条件的异常处理信息项,或者没有对应的异常处理程序,则异常沿堆栈向上传递到调用函数Function1
(3) Function1接收到异常,重复步骤(1)中的动作.
(4) Function1没有满足条件的异常处理信息项,或者没有对应的异常处理程序,运行库允许调试器访问该异常,则异常沿堆栈方向向上传递到调试器进行异常处理
(5) Function1没有满足条件的异常处理信息项,或者没有对应的异常处理程序,运行库不允许调试器访问该异常, 则运行库引发 UnhandledException 事件。
(6) 如果没有 UnhandledException 事件的侦听器,则运行库转储堆栈跟踪并结束程序。
3 ASP.NET异常处理流程剖析
3-1一般的ASP.NET Web应用程序异常处理流程
一般的ASP.NET Web应用程序在异常发生时,ASP.NET开始执行如上图中的步骤进行异常的捕获和处理:
(1) 被调用函数中发生异常,运行库在该方法关联的异常信息数组中搜索满足条件的异常处理项.
a) 当前执行指令在受保护的代码块描述范围内
b) 包含异常处理程序或包含处理异常的筛选器
如果存在满足条件的异常处理信息项,则调用对应的异常处理程序.
(2) 被调用函数没有满足条件的异常处理信息项,或者没有对应的异常处理程序,则异常沿堆栈向上传递到调用函数
(3) 发生的异常信息同时存储,可以使用Server.GetLastError对象获取,使用Server.ClearError()进行清除
(4) 异常沿堆栈向上传递到调用函数,如果没有被处理,会直至顶层调用函数
(5) 到达顶层调用函数后,若异常仍没有被处理,则先判断Page类中是否注册了Error事件的处理程序,如果注册了该事件处理程序,则调用Error事件的处理程序
(6) (5)步骤不起作用,检测配置文件和Global.asax文件中的Application_Error,配置文件优先,如果配置文件customErrors节点的mode不等于off且defaultRedirect有相应设置,或者Application_Error没有注册,则调用配置文件中配置的错误处理器.
(7) (6)步骤不起作用,则Application_Error有注册相应的处理程序,则调用Application_Error的处理程序.
(8) (5) ,(7)处理异常可以使用这样子的步骤进行异常信息的显示和处理.
a) 使用 Transfer 方法将控件传输到其他页
b) GetLastError 方法获取错误信息。
c) 进行相应处理
d) 通过调用 Server 对象(HttpServerUtility 类)的 ClearError 方法将该错误清除。
3-2 ASP.NET Ajax中的异常处理流程
在ASP.NET Ajax中可以通过使用一个或多个 UpdatePanel 控件以及一个 ScriptManager 控件更新页面的各个区域。在这里我描述的就是这种Ajax情况下的异常处理流程.当通过使用一个或多个 UpdatePanel 控件以及一个 ScriptManager 控件更新页面的各个区域时,微软提供的Ajax JS类库提供了PageRequestManager 类管理浏览器中的部分页呈现. PageRequestManager具体的使用请见:MSDN,在这里我们注重的看一下异常发生后异常信息是如何进行传递的,如上图所示步骤:
(1) 浏览器发出请求
(2) 处理请求的被调用函数发生异常, 运行库在该方法关联的异常信息数组中搜索满足条件的异常处理项.
a) 当前执行指令在受保护的代码块描述范围内
b) 包含异常处理程序或包含处理异常的筛选器
如果存在满足条件的异常处理信息项,则调用对应的异常处理程序.
(3) 被调用函数没有满足条件的异常处理信息项,或者没有对应的异常处理程序,则异常沿堆栈向上传递到调用函数
(4) 异常沿堆栈向上传递到调用函数,如果没有被处理,会直至顶层调用函数
(5) 到达顶层调用函数后,若异常仍没有被处理,则先判断ScriptManager对象是否注册了AsyncPostBackError事件的处理程序,如果注册了该事件处理程序,则调用ScriptManager对象的AsyncPostBackError事件的处理程序.
(6) 抛出未处理异常到Client端
(7) 客户端通过PageRequestManager注册的endRequest事件程序捕获并处理异常.
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler); //注册endRequest事件程序
function EndRequestHandler(sender, args)
{
if (args.get_error() != undefined)
{
var errorMessage = args.get_error().message;
args.set_errorHandled(true);
//处理errorMessage
}
}
4 ASP.NET异常处理例子
通过第3节中描述的ASP.NET异常处理流程,在这一节给出简单的异常统一处理的例子.
4-1一般的ASP.NET Web应用程序异常处理例子
根据一般的ASP.NET Web应用程序异常处理流程来看,我们不难发现如果要对异常进行统一的处理,大概有下面三种方法:
1.使用配置文件进行异常的统一处理
2.使用Page中的Error事件进行异常的统一处理
3.使用Application_Error进行异常的统一处理
我们通过三个例子来看这三种统一处理异常的方法的使用方式:
4-1-1使用配置文件进行异常的统一处理
(1)使用VS.NET创建一个Web网站ExceptionHandleUseWebConfig
(2)在Web.Config中<system.web>的节点中添加如下设置:
<customErrors mode="On" defaultRedirect="GenericErrorPage.aspx"></customErrors>
(3)添加GenericErrorPage.aspx页面,并在Page_Load页面中添加异常处理代码,详细见GenericErrorPage.aspx
(4)在Default.aspx页面中增加一个按钮,并注册按钮的Click处理程序并调用抛出异常的函数,详细见Default.aspx
(5)运行程序,但点击Default.aspx页面中的按钮时,窗口被转向到GenericErrorPage.aspx页面并显示错误信息.
4-1-2使用Page中的Error事件进行异常的统一处理
(1)使用VS.NET创建一个Web网站ExceptionHandleUsePageError
(2)在Web.Config中<system.web>的节点中添加如下设置:
<customErrors mode="Off" defaultRedirect="GenericErrorPage.aspx"></customErrors>
(3)添加GenericErrorPage.aspx页面,并在Page_Load页面中添加异常处理代码,详细见GenericErrorPage.aspx
(4)增加PageBase类,该类继承自System.Web.UI.Page类,在该类中注册Error事件,代码详细见PageBase.cs文件
(4)修改Default.aspx类使之继承自PageBase类,在Default.aspx页面中增加一个按钮,并注册按钮的Click处理程序并调用抛出异常的函数,详细见Default.aspx
(5)运行程序,但点击Default.aspx页面中的按钮时,窗口被转向到GenericErrorPage.aspx页面并显示错误信息.
4-1-3使用Application_Error进行异常的统一处理
(1)使用VS.NET创建一个Web网站ExceptionHandleUseApplicationError
(2)在Web.Config中<system.web>的节点中添加如下设置:
<customErrors mode="Off" defaultRedirect="GenericErrorPage.aspx"></customErrors>
(3)添加GenericErrorPage.aspx页面,并在Page_Load页面中添加异常处理代码,详细见GenericErrorPage.aspx
(4)在Default.aspx页面中增加一个按钮,并注册按钮的Click处理程序并调用抛出异常的函数,详细见Default.aspx
(5)添加Global.asax文件并在Application_Error中增加代码,详细见Global.asax文件
(6)运行程序,但点击Default.aspx页面中的按钮时,窗口被转向到GenericErrorPage.aspx页面并显示错误信息.
4-2 ASP.NET Ajax中的异常处理例子
当我们通过使用一个或多个 UpdatePanel 控件以及一个 ScriptManager 控件建立一个Ajax Web网站的时候,我们可以通过如下的方法来统一的进行异常处理.
(1)使用VS.NET创建一个Web网站ExceptionHandleUseAjax
(2)在Default.aspx页面中添加UpdatePanel 控件以及一个 ScriptManager 控件, 在UpdatePanel控件中增加一个按钮,并注册按钮的Click处理程序,在click处理程序中调用抛出异常的函数,详细见Default.aspx页面
(3)在Default.aspx页面中添加Javascript脚本,详细见Default.aspx页面中的javascript脚本描述
(4) 运行程序,但点击Default.aspx页面中的按钮时,弹出错误信息
5结束语
写过程序的人都知道,再好的程序都可能存在未能处理的异常情况,因为程序运行的环境和人员的操作方式可以说是千差万别,开发人员在一开始很难把所有的情况都想到,并做相应的处理。所以,开发人员才需要配合测试人员进行协同工作,目的就是尽量较少和消灭(完全消灭当然只是理想情况了)程序中的错误,处理尽可能多的异常情况。但异常不可避免,所以我们应该为我们的应用程序制定一套异常处理机制,即如何更合理的为已经发生的异常善后。本文的描述仅限于.NET环境下ASP.NET项目开发中的一些异常处理,其他平台的道理应该是一样的,只是具体的实现方式不同而已.希望本文能启到抛砖引玉的作用,给出一种解决问题的思路.