异常处理和日志追踪.ppt
第7章 异常处理和日志追踪,在应用程序运行过程中,难免会遇到异常、错误。笔者在开发过程中经常会被一些用户投拆软件出现故障,或者是一些乱七八糟的错误提示。用户并不都是专家,看到这些莫名其妙的错误往往会认为是应用程序不稳定因素所致,笔者的同事此时会振振有次的告知用户:软件出现故障是难免的,微软够强大吧,Windows系统还不是会蓝屏出错。这样的解释并不是没有道理,任何软件都不可能十全十美,问题在于开发人员如何处理错误,如何让应用程序能够无缝的从错误中恢复。本章将讨论如何处理ASP.NET应用程序中的异常、如何追踪错误以及解决一些故障问题。将会讨论结构化异常处理,日志记录以及当出现错误时,如何将用户页面重定向到一个用户友好的提示页面,本章也将介绍如何使用页面追踪和查看ASP.NET页面的诊断信息。,7.1 ASP.NET应用程序异常处理,错误的产生很多时候是开发人员始料未及的,有的错误可能运行了很久才突然被触发。然而也有一些错误是由于开发人员的疏漏所造成的,一个简单的例子是被0除。假如在一个具有很多复杂公式的页面上,要求用户输入有效的数据执行计算,由于没有很好的验证机制,用户如果一不小心输入了一个0作为被除数,ASP.NET将跳转到一个错误页面,如图所示。,7.1.1 异常处理基础,大多数.NET语言都支持结构化异常处理,当一个错误引发时,.NET框架其实创建了一个异常对象用于呈现问题。开发人员可以使用异常处理器来捕捉这个异常对象。假如不使用异常处理器的话,用户代码将会被中止,ASP.NET将显示一个让用户迷惑的错误处理页面。为了演示如何使用结构化的异常处理,本小节创建一个异常处理程序命名为CommError。在Default.aspx页面上添加一个Button控件,为该Button添加一个单击事件,代码如下所示。protected void Button1_Click(object sender,EventArgs e)int x=5;int y=0;/故意被0除,产生一个异常 int z=x/y;,7.1.2 Exception类,上一节的示例中,当产生了被零除的错误后,.NET会创建一个名为DivideByZeroException的异常对象,catch块中将捕获这个异常对象,并执行处理异常的代码块。DivideByZeroException是一个派生自Exception的对象。Exception对象中包含了很多有用的关于异常的信息,如上面示例中的Message属性用于获取异常的描这性信息,表中列出了Exception类中的一些成员描述。,Exception的成员描述,7.1.3 捕捉异常,通常使用try/catch语句块来捕捉异常,如节中的例子所示。当使用catch语句捕捉到一个异常时,都是一个具体类型的异常而不是一个Exception这样的异常基类,具体异常用于描述一个指定类型的错误,例如上一节中的DivideByZeroException异常。在捕捉异常时,可以定义多个catch块,但是只能有一个try块,这一节继续节中的示例,将Button1中的单击事件更改为如下的代码:,7.1.4 异常的嵌套,假定在try块中调用一个来自外部的方法,比如定义了一个用于除法运算的函数,在该函数内部捕捉了DivideByZeroException的异常。然后在另外一个try块中调用这个除法运算的函数,这种方法称为嵌套异常。下面继续节的示例,复制了Button控件和Label控件,在后置代码中创建二个除法运算的函数,然后在Button按钮的单击事件中调用这个函数,,7.1.5 自定义异常,如果系统提供的异常类已经不能够满足应用系统开发的需要,或者开发团队需要一套自定义异常处理机制,可以创建自定义的异常类。为创建自定义异常类,应该直接或间接地继承自ApplicationException类。自定义异常类应该有良好的命名,一般建议的名称是:错误的描述性名称+Exception。自定义异常类应该定义三个构造函数:默认构造函数、接收错误消息的构造函数、接收错误消息和内部异常对象的构造函数。,7.1.6 Finally语句块,不论是否捕捉到异常,finally块中的代码一定会执行。举个例子,在处理文件时,如果打开了一个文件,执行一些写入操作,这时发生了致命错误,由于catch块捕捉到异常后,控制权会直接跳转到异常处理结尾,那么,这时这个打开的文件便一直没有被关闭。显然这会造成资源占用,如果文件是以独占的方式被打开的话,其他操作将无法顺利进行。另外一个比较常见的例子是数据库操作,如果正在执行一个行级锁定更新时,发生了异常,那么,这会导致这个锁一直不能被释放,继而影响到其余的步骤无法顺利进行。,7.2 记录异常,Web应用程序的用户可能成千上万,有些时候除了向用户显示错误信息之外可能还需要将异常记录下来,比如Web服务器负载过重,一些问题间歇性的多次出现等等。.NET框架提供了多种日记志工具,比如可以在错误产生时发送E-Mail,添加到数据库记录或者是读写文件。一个较好的处理方式是使用Windows事件,Windows事件程序是Windows内置的用于记录系统或者是应用程序日志的一个工具。这个工具可以被任何应用程序使用。,7.2.1 查看Windows事件日志,启动Windows事件查看器,点击“开始|设置|控制面板|管理工具”菜单,选择事件查看器,将弹出如图7.9所示的事件查看器窗口。事件查看器在不同的系统中可能有些不同,系统内置的事件分类有应用程序、安全性、和系统,如果是Windows Vista或者是Windows Server 2008,还多了一个安装分类,这些日志类型的说明如下:应用程序:用于记录任何应用程序的错误或者是通知,异常通常在可以在应用程序日志中记录ASP.NET应用程序异常。安全:用于记录安全相关的问题,仅由操作系统使用。系统:用于记录跟操作系统相关的事件。安装:用于记录安装Windows更新或者是安装其他软件,在Windows Vista中可用。,7.2.2 写入事件日志,System.Diagnostics命名空间下提供了可以读写事件日志的类,开发人员可以使用这个命名空间中的类将ASP.NET异常信息写入事件日志中,下面举一个示例演示在ASP.NET中如何写入事件日志,本示例中将提供一个除法运算输入框,当运算出现任何异常时,将异常信息写入事件日志。(1)新建一个ASP.NET Web站点,命名为EventLogDemo,在Default.aspx中添加两个TextBox控件和一个Button与Label控件,布局效果如图7.13所示。(2)当单击运算按钮时,将从两个文本框中获取数据,并执行乘法运算。如果运算中有任何异常,则在Label控件中显示错误信息,并将异常消息写入事件日志,,7.2.3 自定义日志,自定义的日志是指属于自己的分类的日志,比如可以创建一个属于本程序特有的错误分类。笔者创建了一个ASPNET35BookDemo的事件分类,如图所示。,7.2.4 编程查看事件日志,可以使用ASP.NET将事件日志呈现在Web页上,这样系统维护人员不用必须跑到Web服务上去检查应用程序产生的日志。下面继续以上一小节中的事件日志为例,为其添加一个显示指定日志的事件日志项的页面。(1)右击EventLogDemo示例程序,选择“添加新项”菜单项,在弹出的添加新项窗口中选择“Web窗体”项,命名为ShowEventLog.aspx,单击确定按钮关闭窗体。在该示例中,将使用一个GridView控件来显示事件日志信息,因此在设计视图上从工具箱的数据栏中拖一个GridView控件到页面上。(2)为了获取事件日志信息,笔者新建了一个名为myEventLog.cs的类文件,在该文件中创建了一个单表单个日志项的myEventLog类和代码列表项的LogList类,,7.3 错误页面,错误页面用于描述当前页面中未被处理的错误,当在进行ASP.NET项目开发时,开发人员将面对大量的错误页面来进行调试和处理。错误页面对于在开发过程中诊断错误是非常有用的,因为其中包含了大量关于产生错误的信息。图7.18显示了一个由笔者故意产生的错误页面,新建一个ASP.NET Web项目命名为ErrorPageDemo,在Default.aspx的Page_Load事件中添加如下的程序代码:protected void Page_Load(object sender,EventArgs e)/直接抛出一个未经处理的异常,由ASP.NET显示一个错误信息页面 throw new Exception(错误页面);,7.3.1 错误模式,图7.18是笔者在本地机器上产生错误的错误页面,对远程用户来说,则有不同。出于安全性考虑,通常不希望在远端的用户看到错误页面源代码列表等。ASP.NET中,可以在web.config配置文件中的配置节中配置错误页面的显示方式,当开发人员新建一个ASP.NET Web站点时,的配置节如下代码所示。节可以配置相应的处理步骤。具体说来,开发人员通过该节可以配置 要显示的 html 错误页 以代替错误堆栈跟踪。-,7.3.2 自定义错误页面,在节中列出的由VS2008生成的节的代码中,还具有两个非常有用的子节点。该节点指定当发生指定的错误时,将页面重定向到一个定义好的错误页面。比如当发生403错误时,将页面重定向到NoAccess.htm页面。当然开发人员不可能为所有的错误都单独创建一个错误页面,这将是一个非常巨大的工程。并且IIS己经为Web应用程序中的错误提供了多个错误的页面,,7.4 页面追踪,尽管ASP.NET的错误页面提供了非常有用的信息,但是有时候开发人员需要更详细的信息来修正应用程序中的错误。比如应用程序执行一个属性或者是追踪应用程序中的逻辑错误。有时候应用程序可能生成了一些无效的数据,但是并没有明显的异常触发。ASP.NET提供了追踪功能,让开发人员使用一种更方便和有弹性的方式来报告诊断信息。,7.4.1 启用页面追踪,为了使用追踪功能,开发人员需要显示的允许页面追踪,有几种方法可以启用追踪功能,最常用的方法是在ASP.NET的页面声明区添加一个Trace=true的属性,如下代码所示。也可以使用Page对象的Trace属性,这是一个类的实例,例如下面的代码在Page_Load事件处理器中启用页面追踪功能。protected void Page_Load(object sender,EventArgs e)/启用页面追踪功能=true;,7.4.2 页面追踪信息,ASP.NET的追踪提供了大量的诊断信息,下面依次进行详细的理解:1请求详细信息2跟踪信息3控件树4会话状态和应用程序状态5请求Cookie集合和响应Cookie集合6标头集合7窗体集合8Querystring 集合9服务器变量,7.4.3 写入页面追踪信息,默认的追踪日志提供了大量重要的信息允许开发人员监视应用程序,有时可能想写入自定义的追踪消息。有时开发人员可能想在程序的不同执行点记录变量的多个值,或者是代码到达某个执行点时输出一些消息以便于检查执行过程。通常开发人员使用VS的调试器来完成类似的功能,但是使用追踪也可以完成类似的功能,特别是对于一些由于Web应用程序己经部署的场合,使用追踪是非常有意义的。为了写入一个自定义的追踪消息,可以使用Trace对象的Write方法或者是Warn方法。这两个方法功能基本相同,唯一的区别在于Warn方法将用红色的文字显示错误消息来进行突出显示,下面为PageTrace示例中的Button控件的Click事件添加了如下的代码:protected void Button1_Click(object sender,EventArgs e)Trace.Write(在Session中放置一个条目);SessionTest=Contents;Trace.Warn(己经放置了一个条目在Session中);,7.4.4 应用程序页面追踪信息,使用应用程序级追踪,可以让开发人员追踪整个应用程序,但是追踪信息并不显示在页面,而是被收集和保存在内存中一小段时间。可以通过请求一个特定的URL来查看最近的追踪信息。使用应用程序级追踪有几个好处,首先追踪信息将不会被格式化或者是布局Web页面而搅乱,其次是比较来自不同请求的追踪信息。为了使用应用程序级追踪,需要修改web.config文件中的设置,如下所示。,7.5 小结,本章介绍了在ASP.NET中如何进行异常处理和日志追踪。首先讨论了异常处理的基础,详细介绍了Exception类,如何在ASP.NET应用程序中捕捉未处理的异常,如何进行异常的嵌套,以及如何自定义异常。并讨论了无论程序代码如何执行都必须执行的Finally语句块。接下来讨论了如何在应用程序日志中记录异常,讨论了Windows事件日志查看器的使用,如何向事件日志中写入日志项,如何自定义事件日志,并讨论了以编程的方式查看事件日志。本章也讨论了当应用程序出现错误时,如何为将错误重定向到一个用户友好的错误页面。讨论了错误的几种模式,如何自定义错误页面。本章最后介绍了页面追踪技术,可以使用页面级的追踪和应用程序级的追踪。应用程序级的追踪可以追踪多个请求的信息。而页面级追踪只能追踪本页面的追踪信息。,