Tracing is
an easy way to find out what is going on in your program. Back in the
days of classic ASP, the only way to trace what was happening in your
code was to insert Response.Write
statements in
strategic places. This allowed you to see that you had reached a
known point in the code, and perhaps to display the value of some
variables. The big problem with this hand-tracing technique, aside
from the amount of work involved, was that you had to laboriously
remove or comment out all those statements before the program went
into production.
ASP.NET provides better ways of gathering the trace information. You can add tracing at the application level or at the page level. With application-level tracing, every page is traced, while with page-level tracing, you choose the pages to which to add tracing.
To add
page-level
tracing, modify the Page
directive at the top of the
.aspx page, by adding a
Trace
attribute and setting its value to
true
, as follows:
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false"
Inherits="DebuggingApp.WebForm1" Trace="true"
%>
When you view this page, there will now be tables at the bottom that contain a wealth of information about your web application. Select a book from the drop-down list and you will see something like Figure 7-2.
The top section, labeled Request Details, shows basic information,
including the SessionID, the Time of Request, Request Type, and
Status Code. Every time the page is posted to the server, this
information is updated. If you change the selection (remember that
AutoPostBack is set to true
), you will see that
the Time of Request is updated, but the SessionID remains constant.
The next section, labeled Trace Information, is the trace log , which provides lifecycle information. This includes elapsed times, in seconds, since the page was initialized (the From First(s) column) and since the previous event in the lifecycle (the From Last(s) column). You can add custom trace information to the trace log, as explained later in this chapter.
Table 7-1. Status codes
Category |
Number |
Description |
---|---|---|
100 |
Continue | |
101 |
Switching protocols | |
200 |
OK | |
204 |
No Content | |
301 |
Moved permanently | |
305 |
Use proxy | |
307 |
Temporary redirect | |
400 |
Bad request | |
402 |
Payment required | |
404 |
Not found | |
408 |
Request timeout | |
417 |
Expectation failed | |
500 |
Internal server error | |
503 |
Service unavailable | |
505 |
HTTP version not supported |
The next section in the trace lists all the controls on the page in a hierarchical manner, including the name of the control, its type, and its size in bytes, both on the page and in the ViewState state bag.
This is followed by itemizations of the Cookies and Headers collections. Finally there is a list of all the server variables.
You
can add custom information to the trace
output by writing to the Trace object. This object exposes two
methods for putting your own statements into the trace log,
Write
and
Warn
. The only
difference between the two methods is that Warn
writes to the log in red. The Warn
and
Write
methods are overloaded to take either a
single string, two strings, or two strings and an exception object.
The following cases illustrate:
Trace.Warn("Warning Message")
Inserts a record into the trace log with the message passed in as a string.
Trace.Warn("Category","Warning Message")
Inserts a record into the trace log with the category and message you pass in.
Trace.Warn("Category","Warning Message", excp)
Inserts a record into the trace log with a category, warning message, and exception.
Example 7-5 contains the C# source code, and Example 7-6 contains the VB.NET source code for the Page_Load and ddlBooks_SelectedIndexChanged event procedures; this adds three messages to the trace. Changed lines of code are indicated in boldface.
Example 7-5. Writing to the Trace object in C#
private void Page_Load(object sender, System.EventArgs e) { // Put user code to initialize the page hereTrace.Write("In Page_Load");
if (! IsPostBack) {Trace.Write("Page_Load", "Not Postback.");
// Build 2 dimensional array for the lists // First dimension contains bookname // 2nd dimension contains ISBN number string[,] books = { {"Programming C#","0596001177"}, {"Programming ASP.NET","1234567890"}, {"WebClasses From Scratch","0789721260"}, {"Teach Yourself C++ in 21 Days","067232072X"}, {"Teach Yourself C++ in 10 Minutes","067231603X"}, {"XML & Java From Scratch","0789724766"}, {"Complete Idiot's Guide to a Career in Computer Programming","0789719959"}, {"XML Web Documents From Scratch","0789723166"}, {"Clouds To Code","1861000952"}, {"C++: An Introduction to Programming","1575760614"}, {"C++ Unleashed","0672312395"} }; // Now populate the lists. int i; for (i = 0; i < books.GetLength(0); i++) { // Add both Text and Value ddlBooks.Items.Add(new ListItem(books[i,0],books[i,1])); } } } private void ddlBooks_SelectedIndexChanged(object sender, System.EventArgs e) {// TestMethod( );
try
{
int a = 0;
int b = 5/a;
}
catch (System.Exception ex)
{
Trace.Warn("UserAction","Calling b=5/a",ex);
}
// Check to verify that something has been selected. if (ddlBooks.SelectedIndex != -1) { lblDdl.Text=ddlBooks.SelectedItem.Text + " ---> ISBN: " + ddlBooks.SelectedItem.Value; } }
Example 7-6. Writing to the Trace object in VB.NET
Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page hereTrace.Write("In Page_Load")
If Not IsPostBack Then ' Build 2 dimensional array for the lists ' First dimension contains bookname ' 2nd dimension contains ISBN numberTrace.Write("Page_Load", "Not Postback.")
Dim books(,) As String = { _ {"Programming C#", "0596001177"}, _ {"Programming ASP.NET", "1234567890"}, _ {"WebClasses From Scratch", "0789721260"}, _ {"Teach Yourself C++ in 21 Days", "067232072X"}, _ {"Teach Yourself C++ in 10 Minutes", "067231603X"}, _ {"XML & Java From Scratch", "0789724766"}, _ {"Complete Idiot's Guide to a Career in Computer Programming", _ "0789719959"}, _ {"XML Web Documents From Scratch", "0789723166"}, _ {"Clouds To Code", "1861000952"}, _ {"C++: An Introduction to Programming", "1575760614"}, _ {"C++ Unleashed", "0672312395"} _ } ' Now populate the lists. Dim i As Integer For i = 0 To books.GetLength(0) - 1 ' Add both Text and Value ddlBooks.Items.Add(New ListItem(books(i, 0), books(i, 1))) Next End If End Sub Private Sub ddlBooks_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ddlBooks.SelectedIndexChanged' TestMethod( )
Try
Dim a As Integer = 0
Dim b As Integer = 5 / a
Catch ex As System.Exception
Trace.Warn("UserAction", "Calling b=5/a", ex)
End Try
' Check to verify that something has been selected. If ddlBooks.SelectedIndex <> -1 Then lblDdl.Text = ddlBooks.SelectedItem.Text & " ---> ISBN: " & _ ddlBooks.SelectedItem.Value End If End Sub
The first message is added in the
Page_Load
method to signal that
you’ve entered that method:
Trace.Write("In Page_Load");
The second message is added if the page is not a postback:
if (! IsPostBack) { Trace.Write("Page_Load", "Not Postback.");
This second message is categorized as Page_Load; using a category can
help you organize the trace output. The effect of these two
Write
statements is shown in Figure 7-3. Shading was added to make it easy to see
these two statements.
The third message is added to demonstrate the process of inserting an
exception into the
error log. The
ddlBooks_SelectedIndexChanged event handler also contains code to
force an exception by dividing by zero. The code catches that
exception and logs the exception with a trace
statement, as shown by the following code fragment:
try { int a = 0; int b = 5/a; } catch (System.Exception ex) { Trace.Warn("UserAction","Calling b=5/a",ex); }
Exceptions are an advanced error handling technique that allows you
to try
potentially dangerous code and
catch
any exception objects thrown by the
operating system or by other parts of your own code. You might use
exceptions when reading a file; if the file cannot be opened, the
system will throw an exception. Exception handling is beyond the
scope of this book, but is covered in Jesse
Liberty’s book
Programming
C#
(O’Reilly).
The output from this trace
statement is shown in
Figure 7-4.
Because this trace
statement was written calling
the
Warn
method rather than the
Write
method, the trace output appears in red
onscreen (though not in your copy of this book). Notice that string
you passed in, Calling b=5/a,
is displayed,
followed by an error message extracted automatically from the
exception object.
Not only is it easy to implement trace
statements,
but when it is time to put your page into production, all these
statements can remain in place. The only modification you need to
make is to change the
Trace
attribute in the Page directive from
true
to
false
.
Application-level tracing applies to all the pages in a given application. It is configured through the web.config file, which will be described more fully in Chapter 20.
The web.config file is typically located in the virtual root directory of the application. If there is a web.config file in a subdirectory of the virtual root, then that copy will apply only to the pages in that subdirectory and in the subdirectories under it. If tracing is enabled application-wide from the root directory, tracing will be applied across the application uniformly. The exception is when a specific page has a contradictory page directive, which supersedes the application directive.
Web.config is an XML file that
consists of sections delimited by tags. The trace configuration
information is contained in the <trace>
section within the <system.web>
section,
which is contained within the
<configuration>
section.
Web.config
, like all XML documents, must consist
of well-formed XML. The elements of a well-formed XML file are
discussed in a sidebar in Chapter 4. Note that XML
is case-sensitive.
A typical trace configuration snippet will look something like Example 7-7.
Example 7-7. Trace code snippet from web.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> . . . <trace enabled="true" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
You can easily edit the web.config file in VS.NET by double-clicking on the file in the Solution Explorer. (If the Solution Explorer is not visible, click on the View/Solution Explorer menu item.) Alternatively, this file can be edited in any text editor.
There are five possible properties in the
<trace>
section. These properties appear in Table 7-2.
Several of these properties affect the trace viewer, which will be
described in the following section.
Table 7-2. Trace section properties
If
application-level tracing is enabled,
the trace log can be viewed directly from
your browser for any application, even across multiple page requests.
The trace facility provides a trace viewer,
called trace.axd
. Aim your browser toward
trace.axd
as though it were a page in the
application, with the following URL, for example:
http://localhost/DebuggingApp/trace.axd
You will see a summary of all the entries in the trace log, as shown in Figure 7-5.
Clicking on any of the View Details links will bring you to the same page as would be seen in page-level tracing for that page.
18.117.158.165