Debugging an ASP.NET Web Application, Part I - Tracing...
Bugs are a fact of the programmer's life. How can we deal with them efficiently? In this series of two
articles I'm going to look at two main areas of finding and fixing errors in your program - Tracing and
By: Chris Sully
Date: May 31, 2003
Printer Friendly Version
Bugs are a fact of the programmer’s life. How can we deal with them efficiently? In this series of 2 articles
I’m going to look at two main areas in order to address this question:
- Tracing: the process of collecting information about a program’s execution and
- Debugging: the overlapping topic of finding and fixing errors in your program
We shall look both at the inherent supporting features provided by the .NET framework and ASP.NET and the
additional tools provided by VS.NET over the course of the two articles.
Part I shall focus on Tracing, Part II on Debugging, though as I’ve already stated these are overlapping areas
as you shall see.
Tracing is the ability of an application to generate information about its own execution. The idea is that
subsequent analysis of this information may help us understand why a part of the application is not behaving as
it should and allow identification of the source of the error.
We shall look at two different ways of implementing tracing in .NET
- via the System.Web.TraceContext class
- via the System.Diagnostics.Trace and System.Diagnostics.Debug classes
Tracing can be thought of as a better (more featureful and automated) alternative to the response.writes you
used to put in your old ASP3.0 code to help debug pages!
The TraceContext class is responsible for gathering the execution details of a web request. The TraceContext
object for the current request can be accessed through the Trace property of the Page class. You are thus able
to access the functionality exposed by the object’s members, for example writing to the trace log.
By default, tracing is not enabled. It may be enabled at the page level via the Trace attribute of the Page
directive. When set to true the page appends the tracing information of the current Web request to its output.
The output of a page with the trace attribute set to ‘true’ will include a host of information in addition to
the actual page output, as follows:
Request details: summary details of the page request
Trace information: messages either generated by the ASP.NET engine or by you the programmer by making
use of the Write or Warn methods in code. Four column output: Category, Message, Time from the first trace
item, Duration of this trace item.
Control tree: the entire collection of controls in the ASP.NET page displayed hierarchically.
Collection information: any defined members of the following collections will also be displayed:
- Session state
- Server variables
When tracing is enabled the programmer may add information to the trace information section above via the
trace.warn and trace.write. The only difference between these methods is that the warn method displays its
text in red, thus allowing the programmer a basic facility to differentiate between the severity of tracing
messages. Finally at the page level you may change the order of presentation of trace messages from the default
time order (‘SortByTime’) to be based on an alternate via the TraceMode attribute. In fact the only other
option is ‘SortByCategory’.
As well as enabling tracing at the page level it can be enabled at the application level using the trace
element within the web.config file. This introduces an extra facility: it allows viewing of trace information
in a separate page instead of displaying it with the page output. This page is trace.axd which will be located
in the application root and is termed ‘trace viewer’ – it lists all the page requests to an application along
with summary details and a link to view the full trace log of the request. It also includes a link to clear
the current trace information of all page requests.
Note that the page level directive overrides the application level setting. So if you disable tracing for a
particularly page you will not see corresponding information via trace.axd.
You can imagine this facility is quite a resource hit and should be used wisely. In particular the facility
should be disabled before deployment of the application, when it should be redundant anyway!
Let’s finish of this section with a few examples:
1. Use of trace.write/ trace.warn:
2. Setting up page level tracing by category:
<% @Page Language="VB" Trace="True" TraceMode="SortByCategory" %>
3. Setting up application level tracing (syntax):
Setting localOnly to true makes the trace viewer (trace.axd) available only on the host Web server. The
requestLimit is the number of trace requests to store on the server. The default is 10.
Tracing in VB.NET can also be implemented via generating messages with the use of the Debug and Trace classes.
The messages generated by default by these classes are viewable in the VS.NET Output Window, though you will
see this is configurable shortly.
The two classes are closely related. All their members are conditionally compiled on the basis of whether the
DEBUG or TRACE symbols are specified respectively. Visual Basic .NET/ VS.NET provide two basic configurations
for a project – Debug (the default) and Release. When you compile a program using the Debug configuration both
the TRACE and DEBUG conditional compilation symbols are defined, i.e. when you compile the project any DEBUG
or TRACE code in your application will be included and compiled. In the Release configuration only trace
information is compiled. These modes are configurable via the property pages of your VS.NET solution. They may
also be specified within the program and via command line compilation options.
Some of the members of the debug and trace classes you may choose to use are:
Assert: checks for a condition and displays a message if false
Fail: displays an error message
Indent / unindent: increases / decreases the current indent level by one
Write / WriteIf / WriteLine / WriteLineIf: write information to the trace listeners
in the listeners collection - conditional or unconditional; with a newline character or without.
Debug.Assert(value<0, "Invalid value","negative value employed in debug mode")
Trace.Writeline(value,"Program trace, value of value")
Listeners: the collection of listeners that is monitoring the trace output
See the SDK documentation for full details of the members available.
Which brings us nicely to …
Listeners are the classes for forwarding, recording or displaying messages generated by the Trace and Debug
classes. You can have multiple listeners associated with the Trace and Debug classes by adding multiple
listener objects to their Listeners property.
The Listener property is a collection capable of holding objects of any type derived from the TraceListener
class. This is an abstract class that belongs to the System.Diagnostics namespace that has three implementations.
- DefaultTraceListener: an object instantiated from this class is automatically added to the Listeners
collection of the Trace and Debug classes. It writes messages to the Output window.
- TextWriterTraceListener: writes the messages to any class that derives from the stream class. This includes
the console or a file.
- EventLogTraceListener: writes the messages to the windows event log.
Here’s a brief code snippet relating to implementation 2:
'Create a new text writer using the output stream, and add it to
'the trace listeners.
Dim myFile As Stream = File.Create("TestFile.txt")
Dim myTextListener As New TextWriterTraceListener(myFile)
'Write output to the file
Trace.Write("Test output ")
If you require a listener object which acts differently to these you can create your own class, deriving from
the TraceListener class to do so.
You may also add TraceListeners from your application web.config file, e.g.
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener,System" initializeData="c:\myListener.log" />
Any trace information enabled would then be written to the specified file.
Trace switches allow you to set the parameters that can control the level of tracing that needs to be performed
within a program. These are set via an XML-based configuration file, the web.config file in fact. This might be
particularly useful if the application is in production mode and develops a fault you need to resolve. You could
instruct a program to generate particular trace messages simply by altering the config file. The changes, as in
most situations with .NET, will be picked up automatically.
There are two predefined classes for creating trace switches: the BooleanSwitch class and the TraceSwitch
class – both derive from the abstract Switch class. As ever, you could also define your own class by deriving
from the Switch class.
The BooleanSwitch class differentiates between two modes of tracing: on (non zero) and off (zero, default). In
comparison the TraceSwitch class provides 5 different levels of tracing switches defined by the trace level
enumeration with the following members:
Where each adds an extra level of information to the output.
In your code you could have the following:
dim ts as TraceSwitch([DisplayName],[Description])
If ts.traceVerbose then
debug.writeline(“Nasty big error!”)
and you could configure web.config with the following:
<add name=”[DisplayName]” value=”4” />
Thus, with this configuration verbose error messages will be output. When you don’t want such messages you
would simply reduce the trace level to a lower value within web.config. Remember that the location of the
output of these messages is down to the rest of your system configuration, as described above.
VB.NET provides a set of pre-processing directives which
- enable you to skip sections of source files for compilation, for example to omit testing code in the
released compiled version of your software
- report errors or warnings
- mark sections of your code (a la VS.NET windows form designer)
In addition to the pre-processing directives, VB.NET also provides the programmer with the ConditionalAttribute
class via which you can mark class members for conditional compilation dependent on symbol values. A symbol
value is simply an arbitrary name used for this purpose.
Careful use of these features allow the programmer to keep debugging related code in the source code whilst you
are developing an application but to easily exclude it from the finished compiled code. This will remove the
associated performance hit from production applications. Further, should the production system encounter an issue
you can re-enable the debugging code via a simple switch and recompilation.
Pre-Processing Directives Summary
#If, #Else, #ElseIf, #EndIf: allow conditional skipping of sections of code that will then not be compiled.
#Const: defines a pre-processor constant only viable within a conditional compilation directive.
#ExternalSource, #End ExternalSource: used by the compiler to track line numbers for compiler error
#Region, #End Region: used to mark sections of code. Commonly used by IDEs to show, hide and format code.
ConditionalAttribute Usage example
<Conditional (“DEBUG”)> Public Sub InitializeDebugMode()
In this example, if the symbol is set the Sub will be included in the project compilation. The pre-processing
directives can be used similarly.
The DEBUG and TRACE symbols may be modified by
- modifying the VS.NET project’s property pages
- using the #Const directive at the beginning of the code file
- using the /define (/d for short) option with vbc.exe
You are also not restricted to these two symbols for conditional compilation. You can provide your own custom
defined symbols via the #Const directive.
I hope that the above has proved a useful overview of the tracing related debugging functionality provided by
the .NET Framework and available to the ASP.NET programmer and that you will find these features useful. In the
second part of this series of two articles I shall continue on to examine debugging ‘proper’, in particular the
use of debugging tools.
ASP.NET: Tips, Tutorial and Code
Scott Mitchell et al.
Developing and implementing web applications with VB.Net and VS.Net
Microsoft .NET Framework SDK Documentation
Related Articles on dotnetjohn
ASP.NET Configuration Files