在 ASP.NET 和 Web 服务中调用 Debug.Assert 时自动断点






4.57/5 (12投票s)
2003 年 12 月 23 日
6分钟阅读

88964

587
在 ASP.NET 和 Web 服务中调用 Debug.Assert 时自动断点
引言
Debug.Assert
是开发人员用于创建可靠、无 bug 代码的最强大工具之一。使用 Debug.Assert
时遇到的问题在于编写 ASP.Net 网站或 Web 服务时。默认情况下,对于这些类型的项目,当断言失败时,Visual Studio 会将断言消息记录到调试输出窗口。但仅此而已,没有其他类型的断言失败通知。ASP.Net 和 Web 服务本身不具备在断言失败时中断到调试模式的能力。此示例创建了一个 dll,一旦被 ASP.Net 或 Web 服务应用程序引用,只需在 web.config 文件中添加一小段 xml,就可以让调试器自动中断到您的代码中。
关于断言和本文的说明
在本文中,我假设读者知道如何、为何以及何时使用 Debug.Assert
。不幸的是,断言是一个经常被误解和滥用的调试工具。要了解更多关于断言的信息,请阅读 John Robbins 的《Microsoft .Net 和 Microsoft Windows 应用程序调试》第 3 章。这本书是关于高级调试的绝佳资源。同时,请阅读 MSDN 关于 System.Diagnostic
命名空间的所有内容。
WinForms 和控制台应用程序中的断言
Debug.Assert
是开发人员用于创建可靠、无 bug 代码的最强大工具之一。当 WinForm 应用程序中的断言失败时,默认情况下,您会看到一个消息框(参见图 1),其中显示断言消息、断言失败的堆栈跟踪以及在断言之后的代码行上中断到调试模式的选项。如果单击“重试”按钮,调试器将启动,让您检查导致断言失败的值。
图 1
进入 ASP.Net 和 Web 服务
使用 Debug.Assert 时遇到的问题在于编写 ASP.Net 网站或 Web 服务时。默认情况下,对于这些类型的项目,当断言失败时,Visual Studio 会将断言消息记录到调试输出窗口。但仅此而已,没有其他类型的断言失败通知。ASP.Net 和 Web 服务本身不具备在断言失败时中断到调试模式的能力。
TraceListener
对象概述
TraceListener 类是处理 Debug
和 Trace
类(位于 System.Diagnostic
命名空间中)消息输出的类。Debug
和 Trace
类有一个名为 Listeners 的静态集合对象,该对象包含一个 TraceListener
对象列表。默认情况下,此集合仅包含一个 TraceListener
对象,即 DefaultTraceListener
。 .Net Framework 还包括 TextWriterTraceListener
和 EventLogTraceListener
。当您调用 Debug.Assert
或 Debug.WriteLine
时,运行时会遍历 Debug.Listeners
集合中的每个 TraceListener
,并将您提供的消息发送给每个监听器。因此,如果您将 TextWriterTraceListener
和 EventLogTraceListener
对象都添加到 Debug.Listeners
,您将收到断言消息发送到 Visual Studio 的调试输出窗口、事件查看器和文本文件(您必须通过其构造函数配置每个监听器,但这超出了本示例的范围)。
这与中断断言有什么关系?
解决此问题的方法很酷但极其简单。创建自己的自定义 TraceListener
对象来处理中断到代码。这并不是 TraceListener 类最初的设计目的,但它非常适合我们的需求。为此,请在 Visual Studio 中创建一个新的库项目,并将默认类重命名为 ASPNetDebugAssert
,并让该类继承自 System.Diagnostics.TraceListener。然后重写 TraceListener
基类的 4 个 Write()
和 WriteLine()
方法。在每个重写的方法中,调用 BreakInCode()
。BreakInCode
的代码如下所示。
private void BreakInCode()
{
BooleanSwitch assertSwitch = new BooleanSwitch("BreakOnAssert", "");
if (assertSwitch.Enabled)
{
if (Debugger.IsAttached)
Debugger.Break();
else
Debugger.Launch();
}
}
此方法是 dll 的主力(尽管只是一个很小的)')!它首先基于我们稍后将放在 ASP.Net 或 Web 服务的 web.config 文件中的值创建一个 BooleanSwitch 对象。如果 BooleanSwitch
已启用,它会检查是否已附加调试器。如果调试器已附加到正在运行的进程,则代码将调用 Debugger.Break()
,这将导致 Visual Studio 在 Debug.Assert
调用之后的下一行中断。如果调试器未附加到正在运行的进程,则代码将尝试启动调试器。
这就是全部……嗯,差不多。当您的代码在 ASP.Net 应用程序中调用 Debug.Assert()
并且断言失败时,Debug 类将遍历其集合中的每个监听器,并对每个监听器调用 Write()
方法。当它调用我们的自定义 TraceListener 类时,将指示调试器中断……然后“ Shazam!”……调试器将启动并停止在 ASP.Net 应用程序代码的下一行。
在 web.config 中配置您的 ASPNetDebugAssert
监听器
我们还没有完成。为了使 BreakInCode()
方法正常工作,我们需要在 web.config 文件中放入一些内容。您需要添加以下 xml 块。
<system.diagnostics>
<switches>
<add name="BreakOnAssert" value="1" />
</switches>
<trace autoflush="true" indentsize="0">
<listeners>
<add name="MyListener"
type="ASPNetDebugAssertion.ASPNetDebugAssert,ASPNetDebugAssertion" />
</listeners>
</trace>
</system.diagnostics>
这里的第一项是我们的 BooleanSwitch
的定义。<switches><add> 元素启用或禁用 BooleanSwitch。将 value 属性设置为 0 将禁用该开关,将 1 启用(对于我们的自定义 dll,1 将导致调试器中断,0 不会)。
此 xml 块中的第二项是 <trace> 元素。使用此元素,我们可以在不重新编译代码的情况下将 TraceListener
对象添加到 Debug.Listeners 集合中。我将把这些 web.config 元素的 MSDN 阅读留给您,但应该很明显,此示例将我们的自定义 ASPNetDebugAssert
TraceListener
添加到 Listeners
集合中。
那么我该如何使用它?
这个示例的最后一步是在 ASP.Net 应用程序中实际调用 Debug.Assert
。我们需要做一些事情才能将所有这些结合起来。首先,以 Release 生成模式编译您的 ASPNetDebugAssertion
库。然后,在您的 ASP.Net 或 Web 服务项目中,添加对 dll 的发布版本的引用。(注意:如果您在调试模式下编译 ASPNetDebugAssertion dll,调试器将使用我们 dll 的调试符号,并在调用 Debugger.Break
之后的下一行中断。)接下来,将上面列出的 web.config xml 块复制并粘贴到您的 ASP.Net 项目的 web.config 文件中。请确保将其粘贴到 <configuration> 元素内部,但位于 <system.web> 元素之外。
完成后,您的项目就设置好了,可以进行断言了!在某个 Web 窗体的代码隐藏文件中,添加以下几行代码。
private void Button1_Click(object sender, System.EventArgs e)
{
Debug.Assert(sender == null, "sender obj is null");
string assertTest = "Hey, this worked";
this.TextBox1.Text = assertTest;
}
当应用程序首次启动时,Debug
类将检查 web.config 文件,查看是否应将任何 TraceListeners 添加到其 Listeners
集合中。一旦调用 Debug.Assert
,它将向每个 TraceListener(包括我们的)发送“The assertion worked!!”。当调用我们的 dll 时,BreakInCode()
方法将执行其工作,调试器将在 Debug.Assert
之后的紧邻代码行上中断。就是这样!!!现在,当您使用断言时,调试器就会中断,就像您(几乎)在 WinForm 应用程序中所做的那样。如果您想关闭中断模式,只需将 web.config 中的 BooleanSwitch
定义更改为“0”。