演练:在 Visual Web Developer 中使用跟踪以帮助查找网页错误
更新:2007 年 11 月
有多种方法可查找 ASP.NET 网页中的错误。这其中包括使用调试器和跟踪。跟踪显示有关在页处理过程中所发生的操作的消息,并且可包含您选择要显示的信息。跟踪还提供有关服务器和浏览器正在交换的数据的信息。数据交换包括控件详细信息、服务器变量、用户名、Cookie 等等。本演练演示如何使用跟踪。
如果不可能或不适合使用调试器,则跟踪就很有用。例如,有可能因为网页位于远程服务器上而使得调试器不可用。跟踪还可以使您更方便地查看调试器中未显式提供的信息,例如 HTTP 标头。有关调试的信息,请参见 演练:在 Visual Web Developer 中调试网页。
在本演练中,您将使用跟踪。您将创建一个提示用户输入名称,然后显示该名称的网页。该网页也将名称存储在 Cookie 中,这样用户就不必重新输入名称。
说明: |
---|
在成品应用程序中,存储个人信息更好的技术是使用 ASP.NET 配置文件属性。有关详细信息,请参见 ASP.NET 配置文件属性概述。但是,本演练中使用 Cookie 简化了代码,这可您将重点放在跟踪上。 |
在本演练中,您将故意引入一些错误。然后,您将使用跟踪来查看页处理的状态,这将帮助您诊断这些错误。
本演练涉及以下任务:
为单个页面启用跟踪。
读取跟踪输出。
显示自定义跟踪信息。
在单独的跟踪窗口中查看跟踪信息。
创建自定义跟踪输出。
先决条件
为了完成本演练,您需要:
Microsoft Visual Web Developer Web 开发工具。
.NET Framework。
本演练假设您大致了解如何使用 Visual Web Developer。有关 Visual Web Developer 的介绍,请参见演练:在 Visual Web Developer 中创建基本网页。
创建网站
如果您已经通过完成演练:在 Visual Web Developer 中创建基本网页,在 Visual Web Developer 中创建了一个网站,则可以使用该网站并转至本演练后面的“添加控件”部分。否则,按照下面的步骤创建一个新的网站和网页。
说明: |
---|
本演练假设您所使用的 ASP.NET 页使用代码隐藏文件提供代码。 |
创建文件系统网站
打开 Visual Web Developer。
在**“文件”菜单上单击“新建网站”**。
出现**“新建网站”**对话框。
在**“Visual Studio 已安装的模板”之下单击“ASP.NET 网站”**。
在最右边的**“位置”**框中输入要保存网站网页的文件夹的名称。
例如,键入文件夹名“C:\WebSites”。
在**“语言”**列表中,单击您想使用的编程语言。
单击**“确定”**。
Visual Web Developer 创建该文件夹和一个名为 Default.aspx 的新页。
添加页
如果您正在使用现有网站,则可以创建新页。如果您已经有了可用于本演练的页,请转至下一部分。
创建新页
在解决方案资源管理器中,右击网站名称,再单击**“添加新项”**。
在**“添加新项 <Path>”对话框中的“Visual Studio 已安装的模板”下面,单击“Web 窗体”**。
在**“名称”**框中,键入 FirstWebPage.aspx。
在**“语言”**列表中,单击您想使用的编程语言。
如果您使用 Visual Basic 或 C# 创建页,则选择**“将代码放在单独的文件中”**复选框。
单击**“添加”**。
添加控件
在创建完网站并打开一个页之后,下一步是向该页添加一些控件。
添加要调试的控件和代码
切换到“设计”视图,然后从工具箱的**“标准”**组中,将下列控件拖到页上,然后按照下表设置其属性。
控件
属性
TextBox
ID:textName
Text:(空)
Button
ID:buttonDisplayName
Text:“提交”
Label
ID:labelName
Text:(空)
说明: 对于本演练,页的布局无关紧要。
添加代码
下一步是向页添加代码。当页正确运行时,用户可输入一个名称,然后单击**“提交”**,这将在 Label 控件中显示该名称。如果用户关闭浏览器,然后又返回该页,该页将有该用户的名称,因为该名称存储在 Cookie 中。
下面的步骤指导您添加代码。此处添加代码的过程以及代码本身都不是完全正确的。这是故意为之,以便您将能使用跟踪来查找页上的错误。
添加代码
在解决方案资源管理器中,右击 FirstWebPage.aspx,然后单击**“查看代码”**。
说明: 不要双击“设计”视图中的按钮。
在类定义内,输入下面的代码。
说明: 如果您正在使用单文件页,则将代码粘贴到 <script> 块中。
Protected Sub buttonDisplayName_Click(ByVal sender As Object, _ ByVal e As EventArgs) labelName.Text = Server.HtmlEncode(textName.Text) Response.Cookies("username").Value = labelName.Text End Sub
protected void buttonDisplayName_Click(Object sender, EventArgs e) { labelName.Text = Server.HtmlEncode(textName.Text); Response.Cookies["username"].Value = labelName.Text; }
代码执行下列任务:
它读取 TextBox 控件的值,然后在 Label 控件中显示该值。作为此逻辑的一部分,该代码调用 HtmlEncode 方法,该方法将潜在的可执行 HTML 字符(如右尖括号 (<))转换为对应的显示结果。这是用来防止脚本侵入的一种安全措施。有关详细信息,请参见 脚本侵入。
它创建一个名为 username 的 Cookie,该 Cookie 存储用户输入的值。
将下列方法添加到您在前面的步骤中创建的 Click 处理程序的上面或下面。
Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) _ Handles Me.Load If Not Request.Cookies("username") Is Nothing Then labelName.Text = Request.Cookies("username").Value End If End Sub
void Page_Load(Object sender, EventArgs e) { if(Request.Cookies["username"] != null) { labelName.Text = Request.Cookies["username"].Value; } }
测试该页
现在可以测试页面。如果您按照上一部分的过程中故意设计的不完整步骤来执行,则该页将不会按设计的那样运行。
测试页面
按 Ctrl+F5 运行该页。
当页出现时,在文本框内输入您的名称,然后单击**“提交”**。
注意,即使单击**“提交”**会将该页发送回服务器,您的名称仍然不会显示。
关闭浏览器。
现在您可以使用跟踪来帮助查找页中的错误。
使用跟踪查找错误
在这一部分,您将对该页启用跟踪。您将检查跟踪输出,然后包含将帮助您查明页错误的自定义跟踪消息。
对页启用跟踪
打开 FirstWebPage.aspx 页并切换至“设计”视图。
在“属性”列表中,单击**“DOCUMENT”**。
这将显示该页的属性。
将**“Trace”**设置为 true。
跟踪设置实际上是作为 @ Page 指令的一部分实现的。切换至“源”视图并查看页的第一行,您会看到这一点。@ Page 指令与下面的内容相似:
<%@ Page language="VB" Trace="true" %>
<%@ Page language="C#" Trace="true" %>
按 Ctrl+F5 运行该页。
该页显示在浏览器中。在页的顶部,您将看到您放置在页上的文本和控件。在文本和控件下面,您可以看到跟踪输出,它显示了有关页处理的很多细节,包含下列信息:
页运行时所发生的页事件序列。
页上的控件的类型、名称和大小。
Cookie 及其内容。
服务器变量,它是浏览器发送到服务器的所有信息的集合。
注意,在**“请求详细信息”(跟踪信息的第一块内容)的下面,“请求类型”为“GET”**。这指示这是页的第一次运行;即,它不是回发。
在框中,键入一个名称,然后单击**“提交”**。
“请求类型”现在是“POST”。这指示这是页的回发。单击**“提交”**不会使名称显示。
关闭浏览器。
您可以使用自定义跟踪输出来帮助您了解页的逻辑。
添加自定义跟踪输出
将下面突出显示的行添加到您在本演练前面的“添加代码”部分中创建的 buttonDisplayName_Click 处理程序:
Protected Sub buttonDisplayName_Click(ByVal sender As Object, _ ByVal e As EventArgs) Trace.Warn("debugging", "Start buttonDisplayName Click handler") labelName.Text = Server.HtmlEncode(textName.Text) Response.Cookies("username").Value = labelName.Text Trace.Warn("debugging", "End buttonDisplayName Click handler") End Sub
protected void buttonDisplayName_Click(Object sender, EventArgs e) { Trace.Warn("debugging", "Start buttonDisplayName Click handler"); labelName.Text = Server.HtmlEncode(textName.Text); Response.Cookies["username"].Value = labelName.Text; Trace.Warn("debugging", "End buttonDisplayName Click handler"); }
Warn 方法将您的自定义消息添加到跟踪输出。尽管 TraceContext 类还提供了 Write 方法,但是 Warn 方法更加有用,因为输出是以彩色显示的。
按 Ctrl+F5 运行该页。
单击**“提交”**。
当您检查跟踪输出时,您将注意到输出不包含红色文本。据此您可以推断,**“提交”**的 Click 处理程序未在调用。
未调用处理程序的最常见原因是控件尚未正确绑定到事件处理程序。本例中也是如此——虽然您添加了事件处理代码,但是未将**“提交”**的 Click 事件绑定到处理程序。通常情况下,当双击“设计”视图中的控件时,Visual Web Developer 会将事件绑定到该控件。
关闭浏览器。
在“源”视图中,将下面突出显示的属性添加到 <asp:button> 元素:
<asp:button id="buttonDisplayName" runat="server" text="Submit" onclick="buttonDisplayName_Click" />
按 Ctrl+F5 运行该页。
在框中,输入一个名称,然后单击**“提交”**。
您的自定义跟踪输出以红色显示在**“跟踪信息”**部分中,它列出了该页所经历的处理步骤。
此部分中的输出按照页处理过程中消息的发生顺序显示消息。您在 Click 事件处理程序中添加了自己的消息,该处理程序在 Begin Raise PostBackEvent 和 End Raise PostBackEvent 行之间进行处理。包含自定义消息不仅可以让您知道处理程序已被调用,而且还能让您了解该代码是在页处理周期中的哪个环节执行的。
自定义消息旁边的类别为 debugging,这是您在调用 Warn 方法时指定的类别。您可以指定想要的任何类别,并且如果有用,可将页的 TraceMode 属性设置为 SortByCategory 值以便于在跟踪输出中查找类别。
此外,注意您输入的名称显示在标签中。
现在,**“提交”**的 Click 处理程序已运行正确,可以测试页中其余的代码(包括 Cookie)了。
测试 Cookie
关闭浏览器。
按 Ctrl+F5 运行该页。
您期望的行为是让您输入的名称自动出现在标签中,因为**“提交”**的 Click 处理程序设置了一个 Cookie,并且 Page_Load 处理程序在下一次回发过程中会读取该 Cookie。但是,标签决不会从该 Cookie 设置。
如果您编写了一个 Cookie,但是它不是持久的,则错误通常是您没有为 Cookie 设置一个显式过期日期。没有过期日期的 Cookie 是一个会话 Cookie。会话 Cookie 在浏览器关闭后就不再保留在服务器内存中。换言之,该 Cookie 未写入到浏览器中。在下面的步骤中您将更正此问题。
关闭浏览器。
在“源”视图中,将下面突出显示的行添加到 buttonDisplayName_Click 处理程序中:
Protected Sub buttonDisplayName_Click(ByVal sender As Object, _ ByVal e As EventArgs) Trace.Warn("debugging", "Start buttonDisplayName Click handler") labelName.Text = Server.HtmlEncode(textName.Text) Response.Cookies("username").Value = labelName.Text Response.Cookies("username").Expires= _ DateTime.Now.AddMinutes(30) Trace.Warn("debugging", "End buttonDisplayName Click handler") End Sub
protected void buttonDisplayName_Click(Object sender, EventArgs e) { Trace.Warn("debugging", "Start buttonDisplayName Click handler"); labelName.Text = Server.HtmlEncode(textName.Text); Response.Cookies["username"].Value = labelName.Text; Response.Cookies["username"].Expires= DateTime.Now.AddMinutes(30); Trace.Warn("debugging", "End buttonDisplayName Click handler"); }
新行将 Cookie 显式设置为 30 分钟后过期。
按 Ctrl+F5 运行该页。
在框中,输入一个名称,然后单击**“提交”**。
该名称显示在浏览器中。在**“响应 Cookie 集合”**跟踪输出中,您会看到正在设置该 Cookie。
关闭浏览器。
按 Ctrl+F5 运行该页。
这一次,将自动填入名称。在**“响应 Cookie 集合”**跟踪输出中,现在您可以看到浏览器正在将该 Cookie 传递到您的网页。
在跟踪查看器窗口中显示跟踪信息
如果您只使用单个页,将页设置为显示跟踪输出会非常有用。但是,如果您在应用程序中使用了多个页,则为每个页启用和禁用跟踪就可能不太方便。而且,当页正在运行时在页中显示跟踪输出信息会造成混乱。无论如何,您不会希望页对应用程序用户显示跟踪输出。
您不仅可以在页一级配置跟踪,还可以在应用程序一级进行配置。设置应用程序级跟踪有两个好处:
您可以同时为所有页启用和禁用跟踪。
您可以在单独的浏览器窗口(跟踪查看器)中显示跟踪输出,而不是将其作为页输出的一部分显示。
启用应用程序级跟踪后,ASP.NET 会将所有页的跟踪输出保留在缓存中。您可以设置选项来指定缓存多少页的跟踪输出,以及设置您是希望保留最新的项还是最旧的项。然后,您可以在浏览器中调用跟踪查看器并选择要检查的跟踪输出。
在演练的这一部分中,您将启用应用程序级跟踪并使用跟踪查看器检查跟踪输出。
启用应用程序级跟踪
切换至“源”视图,然后在页顶部的 @ Page 指令中删除 Trace="true"。
说明: 应移除该属性;不要只是将其设置为 false。否则,本演练的后续步骤将不会正确工作。
在**“网站”菜单上单击“ASP.NET 配置”**。
出现“ASP.NET 网站管理”工具。
单击**“应用程序配置”**。
在**“调试和跟踪”下,单击“配置调试和跟踪”,然后选择“捕获跟踪信息”**复选框。
此设置启用应用程序级跟踪。
对于本演练,您可以将其余设置保留为默认值。ASP.NET 将缓存最多 10 个跟踪输出项(对于单页,可以有 10 个回发,对于多页,每页的回发数更少),并缓存最新的项。
关闭 ASP.NET 网站管理工具。
现在您可以运行原始页,并以用户查看方式使用它。但是,如有必要,您可以同时在单独的浏览器窗口中查看跟踪输出。
在单独的浏览器窗口中查看跟踪输出
按 Ctrl+F5 运行该页。
注意该页不再显示跟踪输出。该页显示为用户将看到的样子。
在框中输入一个名称,然后单击**“提交”**以确认该页运行正确。
打开一个新的浏览器窗口。
在浏览器的**“地址”**框中,键入站点的 URL,用 trace.axd 替换您正在使用的页的名称。
例如,如果页的 URL 为:
https://localhost:8081/WebSite/Default.aspx
键入下列内容:
https://localhost:8081/WebSite/trace.axd
说明: 执行此任务的快速方式是复制原始页的 URL,然后只更改页名称。
浏览器显示当前缓存的跟踪项。
对最后(最新)的跟踪项单击**“查看详细信息”**。
浏览器显示的跟踪输出与您在本演练的前面部分中所看到的输出类似,不同之处在于这些输出不是追加在页的结尾。
切换到包含原始页的浏览器实例。
在框中键入一个新名称,然后单击**“提交”**。
此操作将生成一个新的跟踪日志项。
切换到包含信息的浏览器实例。
在浏览器中,单击**“后退”返回到列表跟踪项,然后单击“刷新”**更新项列表。
出现一个新项,表示您在步骤 7 中创建的跟踪输出。
关闭这两个浏览器窗口。
创建自定义跟踪输出
如您所见,跟踪输出包含很多信息,有时比您所需要的还要多。例如,您可能想将跟踪输出限制为只是您自己创建的跟踪输出。跟踪可让您读取跟踪缓冲区的内容,并有选择地显示您所需要的信息。
若要创建自定义跟踪输出,请处理 Trace 对象的 TraceFinished 事件。在相应的事件处理程序中,您可以读取跟踪缓冲区。
创建自定义跟踪输出
在您已使用的页中,将下面突出显示的代码添加到 Page_Load 处理程序中:
Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Load If Not Request.Cookies("username") Is Nothing Then labelName.Text = Request.Cookies("username").Value End If AddHandler Trace.TraceFinished, AddressOf Me.TraceFinished If IsPostBack Then Trace.Write("debugging", "Page_Load (Postback)") Else Trace.Write("debugging", "Page_Load (First Time)") End If End Sub
void Page_Load(object sender, EventArgs e) { if(Request.Cookies["username"].Value != null) { labelName.Text = Request.Cookies["username"].Value; } Trace.TraceFinished += new TraceContextEventHandler(this.TraceFinished); if (Page.IsPostBack) { Trace.Write("debugging", "Page load (postback)"); } else { Trace.Write("debugging", "Page load (first time)"); } }
该代码执行以下两个功能:
它将页中的一个方法绑定到 Trace 对象的 TraceFinished 事件,当该页的跟踪输出完成时会引发该事件。您将在下一步中编写该方法。
它写入一些跟踪信息。
创建下面的方法以处理 TraceFinished 事件:
Sub TraceFinished(ByVal sender As Object, _ ByVal e As TraceContextEventArgs) Dim traceRecord As TraceContextRecord For Each traceRecord In e.TraceRecords If traceRecord.Category = "debugging" Then Response.Write("<BR>" & traceRecord.Message) End If Next End Sub
void TraceFinished(object sender, TraceContextEventArgs e) { foreach(TraceContextRecord traceRecord in e.TraceRecords) { if(traceRecord.Category == "debugging") { Response.Write("<br>" + traceRecord.Message); } } }
此代码在跟踪输出完成时执行。跟踪缓冲区可以作为集合在 e 事件参数的 TraceRecords 属性中使用。代码遍历该集合,并显示类别为 debugging 的任何跟踪记录的值;在本演练中,您已将所有自定义跟踪输出的类别设置为 debugging。
在演练中,此时,网站已配置为对所有页启用跟踪,但是跟踪输出被定向至跟踪查看器而不是页。如果以另一种方式配置网站(例如,在页中显示跟踪输出),请执行“启用应用程序级跟踪”这一过程(在本演练前面的“在跟踪查看器窗口中显示跟踪信息”部分)中的步骤。
现在可测试自定义跟踪输出。
测试自定义跟踪输出
按 Ctrl+F5 运行该页。
当页显示在浏览器中时,会出现消息**“页加载(第一次)”**,但是未出现其他跟踪输出。
单击**“提交”**。
将出现消息**“页加载(回发)”、“启动 buttonDisplayName Click 处理程序”和“结束 buttonDisplayName Click 处理程序”**。
说明: |
---|
如果超出了在 trace 元素(ASP.NET 设置架构) 的 requestLimit 属性中指定的缓存请求数,则 TraceFinished 事件将不会引发,并且您不会在网页上看到这些消息。 |
后续步骤
本演练已经演示了 ASP.NET 中跟踪的基本功能。除了使用跟踪显示 Web 应用程序内的信息之外,还可以将 ASP.NET 跟踪与其他检测方法集成。例如,您可能希望执行下列操作:
将系统诊断消息作为 ASP.NET 跟踪的一部分显示。
有关更多信息,请参见 演练:将 ASP.NET 跟踪与 System.Diagnostics 跟踪集成。
将 ASP.NET 跟踪信息发送到 .NET Framework 跟踪机制,后者使用 System.Diagnostics 命名空间中的类。
将信息转发到注册的检测侦听器,作为网站运行状况监视的一部分。
有关注册侦听器的更多信息,请参见 <trace> -> <listeners> 元素。