Tracing and Debugging


Microsoft Corporation
October 2003

Applies to
    Microsoft® ASP.NET
    Microsoft ADO.NET
    Microsoft Visual Basic® .NET
    Microsoft Visual Studio® .NET
    Java Server Pages

Summary: Learn the advantages of debugging in Visual Studio .NET when compared to debugging JSP. (8 printed pages)


JSP Tracing and Debugging
ASP.NET Tracing and Debugging


For any developer, tracing and debugging an application involves breakpoints, code stepping, instant watches, and sometimes hours of frustration. The only non-constant is the hours of frustration. Depending on the tools you use to write JSP (or any code, for that matter), tracing and debugging can be a troublesome task. Fortunately, building your applications with Microsoft® ASP.NET using Microsoft Visual Studio® .NET, you can take advantage of the robust tracing utilities built into the language, as well as the comprehensive line-by-line debugging features of Visual Studio .NET.

JSP Tracing and Debugging

System.out Statements

System.out statements allow you to trace and debug your JSP code. For example, you can use System.out statements to see where you are in an application, or use them to return values and see if they are correct. The following code block illustrates a basic example of the System.out statement:

Listing 1. The log() method

// Somewhere in your JSP
   System.out.println("Entering ejb.callMethod");
   result = ejb.callMethod();
   System.out.println("The result is " + result);

In the previous example, we use the System.out statement to print Entering ejb.callMethod to a console before calling the actual method, and then use another System.out statement to print the results of that method call. These three lines of code can tell us quite a bit about our application; they tell us if ejb.callMethod() was actually called (if the second System.out statement prints the results to the console, then we know it was called), as well as help us determine if the output from that method call is correct. This basic illustration of the System.out statement is fundamentally the basis for all JSP tracing and debugging.


The traditional means of tracing and debugging a JSP involves using numerous System.out statements. Although this solution does allow you to trace and debug your application, it also has various drawbacks. For example, if you accidentally forget to remove a tracing statement, and then deploy your application, your users will see those statements, thus taking credibility and professionalism away from your Web site.

The following example illustrates a more advanced solution, where tracing statements are displayed only when the developer wishes them to be displayed (not just when the application is run). In this skeleton example, we have a log() method, and a basic JSP. The following code block illustrates the basic JSP:

Listing 2. Basic JSP

   // This section would contain normal html processing,
   // as well as any business logic.

   log("Before call");
   result = ejb.callMethod();
   log("After Call");
   log("Result = " + result);

The JSP calls the log() method, and depending on the value of the public variable DEBUG_LEVEL, the tracing statements are displayed in the application. The following code block illustrates the log() method:

Listing 3. The log() method

// Somewhere in a base class for all JSPs
public static log(String s) {
   // Change this to the appropriate trace level.
   public Static DEBUG_LEVEL = "ERROR";

   switch (DEBUG_LEVEL) {
   case: ERROR
   case : TRACE
   case : PRODUCTION

In the previous example, the developer has full control over when tracing statements are displayed. Once the application is debugged and ready for production, the developer simply switches the value of DEBUG_LEVEL from ERROR or TRACE to PRODUCTION, and all tracing statements are not displayed in the application (thus saving your users from seeing your tracing and debugging statements). This tracing and debugging logic outlines a much more efficient way of building JSP applications when compared to simply inserting numerous System.out statements throughout your code.

Open Source Projects

To debug JSP applications quickly and effectively requires a solid framework for tracing and debugging. Because debuggers like VisualAge for Java are not always available, sometimes you'll need to build your own custom solution. In such a case, open source projects, committed to the process of providing advice/tools for building custom tracing and debugging solutions can be quite helpful. The following Web sites list only a few of the many useful resources for building a customized tracing and debugging solution:

Tracing and Debugging Tools

There are a host of J2EE development environments which you may use to develop your Web applications; many of which provide excellent tracing and debugging capabilities. Two such examples are Oracle9i JDeveloper and VisualAge for Java.

Oracle9i JDeveloper offers advanced tracing and debugging features, such as the ability to view the status of threads and monitors, the ability to view object instances in the Java heap, the ability to force garbage collection, the ability to customize breakpoint behavior (for several different types of breakpoint), as well as a host of other useful features discussed in the article Oracle9i JDeveloper: Debugging J2EE Applications.

VisualAge for Java offers advanced tracing and debugging features such as the ability to set conditional breakpoints, the ability to specify debugging exceptions, the ability to perform class trace generation, and a host of other useful features discussed at the VisualAge for Java Web site.

Other useful J2EE Development Environments include the following:

ASP.NET Tracing and Debugging

Building your Web applications with ASP.NET in Visual Studio .NET offers many benefits. For example, line-by-line syntax checking at design time; debugging statements no longer have to be removed when you deploy your application; you can easily toggle your applications between debug-mode and deploy-mode; as well as a host of additional features that will be explained in the following sections. Essentially, by using ASP.NET with Visual Studio .NET, you're granted the sophisticated debugging and tracing options that should be expected from a mature integrated development environment.

Page-Level Tracing in Visual Studio .NET

To trace through an ASP.NET application, you use Trace.Warn() and/or Trace.Write(); both have very similar functionality to the Java System.out statement. The Trace.Warn() statement simply displays its output in red text, where the Trace.Write() statement displays its output in black text. These two statements not only allow you to display trace and debug messages, but may also be configured so they don't display their messages in the deployed application (an advantage that will be further discussed later in this section).

To illustrate the functionality of Trace.Warn() and Trace.Write(), we'll create a new C# Web application project in Visual Studio .NET, named TraceDemo . Once the project is created, we will add a button to the application, and the following lines of code to the project's Page_Load() action event:

Listing 4. Trace.Write in ASP.NET

private void Page_Load(object sender,System.EventArgs e)
   Trace.Write("myMessage", "In Page_Load");

The Trace.Write() statement takes two strings; the first is used to categorize your trace statement (that is, help you identify the type of trace statement), and the second is for the message you wish to display. Yet, if we were to run our current TraceDemo application, our Trace.Write() strings would not appear in the application's output; the page will display the button but not the messages. In order for the messages to display in the output, we must explicitly turn tracing on in the application's .aspx file, using the following Page directive:

Listing 5. Tracing with the Page directive

<%@ Page Trace="true" %>

Now when we run the application, our tracing statements (and a host of other useful debugging information) display after the page's regular output.

By simply setting one attribute in our Page directive, we display all trace and debug information, thus illustrating how easy it is to switch our application from debug mode to deploy mode.

The TargetSchema attribute

The previous example contains an oddity. Before running the application with tracing enabled, the page's targetSchema property, which determines how controls are laid out on a Web form, must be changed from Internet Explorer 5.0 (the default) to either Internet Explorer 3.0 or Netscape 4.0. At the time of this writing, the default targetSchema setting produces erroneous results: the tracing information will not display below the regular application's output, but literally underneath. If the targetSchema's default value is not changed, then you will receive obscured output.

Application-Level Tracing in Visual Studio .NET

The previous section illustrated tracing for an individual page, by setting Trace="true" in the page's Page directive. Yet, if we wish to add additional pages to the project, we must manually enable tracing for each additional page—not the most efficient solution. A better solution is to set tracing at the application level, where every page in the application outputs trace and debug information. To set application-level tracing, we must first remove the Trace="true" statements from the page's Page directive. Once these statements are removed, we simply edit the project's web.config file (which houses the configuration settings for the entire project) and set its <trace> tag enabled value to "true". The following image illustrates the updated web.config file:

Listing 7. Web.config trace settings


Now, when we run our application, the trace information is not output to our browser window, but instead is written to a log file behind the scenes. This log file is named Trace.axd, and is placed in the project's virtual directory. To access this log file, go to http://localhost/TraceDemo/Trace.axd, and IIS will render your tracing information.

To examine the details for each request, click the View Details link, and ASP.NET will bring up the trace information for that request.

Additional application-level trace attributes

While the previous example illustrated how to use the <trace> tag's enabled attribute, there are four additional attributes that may be used:

  • RequestLimit determines the number of tracing requests stored by the .axd log file.
  • pageOutput determines whether or not trace information is output to the browser hosting your application (as well as being written to the .axd log file). Setting this attribute to true will display tracing information for every page in the application.
  • traceMode determines how information in the Trace Information section is organized. For example, if the default value (SortByTime) is not changed, then tracing information is displayed by time of triggered events. If the default value is changed to SortByCategory, then action events are listed alphabetically according to their Category headings.
  • localOnly determines if trace information should be accessible to remote machines. To make trace information available to someone other than localhost, you must set this attribute to false.

The greatest advantage of these attributes, and of application-level tracing, is that you may trace your applications while they are live. The information generated by this trace-and-debug process can easily tell you which pages are most often viewed, which pages have the longest processing time, and a host of other useful information.

Debugging ASP.NET with Visual Studio .NET

To illustrate the functionality of the Visual Studio .NET debugger, we'll create a new C# Web application project named DebugExamp. In this project, we will create a basic dictionary. We will add a button labeled Define, and two text boxes (one for the term, and another for the definition). Once we have added our button and text boxes, we must add the following lines of code to the projects Button1_Click() action event:

Listing 8. DebugExamp dictionary application

private void Button1_Click()
   if (TextBox1.Text.Equals("hello"))
      TextBox2.Text = "An expression of greeting.";
      TextBox2.Text = "Definition for " + TextBox1.Text + ".";

This action event simply checks to see if the string entered into TextBox1 is "hello". If the string equals hello, then our definition for that term is displayed. If the string entered into TextBox1 is not "hello", then we simply display the string "Definition for", followed by the name of the term. Press F5 to run the application, ensure that it works correctly, and then close the browser window.

Reload the DebugExamp project in Visual Studio .NET, and set a breakpoint in the application by right-clicking the if() statement from Listing 8. Select Insert BreakPoint from the menu that appears, and Visual Studio .NET will insert a breakpoint and highlight that line of code.

The next time we attempt to run the application using the term "hello", Visual Studio .NET will stop the execution at the line where the breakpoint was inserted, and return us to the IDE. Once inside the IDE, we can step through subsequent lines of code individually (by pressing F11), step over code (by pressing F10), inspect variable values, and perform other trace and debug actions. For example, to examine the characteristics of the application's text box, press ALT+CTRL+Q to invoke the QuickWatch window. This window lists the values of the text box's properties.

In addition, you can see the values of other variables by entering their names into the Expression box of the QuickWatch window. Essentially, this window provides added flexibility when debugging applications, as you can now peek into an application's state during its execution.

Cross-Language Debugging

To illustrate the cross-language debugging features of Visual Studio .NET, we'll build a basic calculator. Instead of hosting all of our application logic in a C# class, we'll also use a Microsoft Visual Basic® .NET class to process our calculations. First, we'll create a C# project named Calculator . In this project, we must insert three text boxes and a single button. The first two text boxes will hold the numbers we wish to add. The single button will trigger our calculation. The final text box will hold our calculation output. After adding these items to the Calculator project, you must create another project. This second project will use Visual Basic .NET. Name this second project MyCalc. Inside MyCalc, add a new Visual Basic class, named VBCalc. Once the file is added to your project, insert the following lines of code into VBCalc:

Listing 9 Visual Basic .NET define Class

Public Class VBCalc
   Public Function Add(ByVal x As Integer, ByVal y As Integer)
      Add = x + y
   End Function
End Class

This class will host our calculation logic. Now that we have coded our Visual Basic .NET logic, we can close this project and reopen our C# Calculator project. In Calculator, we add a new reference to our MyCalc project by right-clicking the References section of the Solution Explorer, and then clicking Add Reference. We then click the Projects tab, navigate to our MyCalc project, and add the reference. The project will now appear in our References section of the Solution Explorer. Now that we have a reference to our Visual Basic .NET project, we can alter our Button1_Click() action event.

Notice that we are not processing our calculation in C#; we are simply creating an instance of the Visual Basic .NET class VBCalc to do our calculation instead. Now, when we run our application, we're combining both C# and Visual Basic .NET logic. We can also debug these two different languages from the same IDE. If we insert a breakpoint where our C# logic calls our Visual Basic .NET function, the Visual Studio .NET debugger will also be able to accommodate our needs.

By pressing F11 (to step into this breakpoint), Visual Studio .NET automatically switches from our code view in C# to our code view in Visual Basic .NET, thus performing cross-language debugging. As you can see, the universality of Visual Studio .NET simplifies debugging considerably when compared to traditional means of cross-language debugging (having separate debuggers for each language in your application).


Although Java and ASP.NET provide almost the same tracing and debugging capabilities, the major difference between the two lies in their ease of use and Visual Studio .NET's cross-language debugging feature. Using Java and JSP, all tracing and debugging functionality must either be handled by the J2EE development environment, or manually coded by you (as illustrated by our example in the section JSP Tracing and Debugging). Using ASP.NET with Visual Studio .NET, the same tracing and debugging features are present, yet you are not required to code that functionality. Visual Studio .NET already provides you with the ability to easily switch from debug mode to production mode, and does not require you to either remove trace statements (when deploying your application) or set up classes that determine how System.out statements should be handled (for example, classes that determine whether or not statements are visible to the user). The second and most prevalent difference between Java and ASP.NET concerns Visual Studio .NET's cross-language debugging capability. Because all .NET languages can be used in Visual Studio .NET, ASP.NET can be combined with other languages, such as Visual Basic .NET or C#. This ultimately grants you added flexibility when building, tracing, and debugging your Web applications. Ultimately, ASP.NET and Visual Studio .NET grant you the advantages of best-practice tracing and debugging, without you having to code that best-practice framework.