Debugging an ASP.NET Web Application, Part II - Debugging...

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 Debugging.


By: Chris Sully Date: July 2, 2003 Download the code.

Introduction

Bugs are a fact of the programmer's life. This is the second of two articles examining how we may deal with them efficiently within .NET. In part I we looked at the process of collecting information about a programs execution (tracing). Tracing is really a part of the overall activity of debugging: finding and fixing errors in your program. In part II of this series we'll focus on debugging and in particular on the tools available to the programmer to simplify the task.

Debugging

Debugging is the process of finding and fixing errors in your application. Without good tools this process can be time consuming. VS.NET comes with a large toolset in this area that we shall consider in this article. I should also point out at this point that the .NET framework ships with a GUI debugger located in \Program Files\Microsoft.NET\FrameworkSDK\GuiDebug\DbgCLR.exe which is rather similar to the VS.NET tool so all is not lost if you do not have a copy of VS.NET. Thus much of what is presented below applies equally to DbgCLR.exe though some of the interface detail may differ slightly. The VS.NET debugger does offer additional features however, as well as offering the advantage of being integrated with the rest of the IDE toolset.

Firstly we should differentiate between two types of errors:

  1. Compile time errors: these are largely syntactic errors which will be captured by the compiler. Note, that use of Option Explicit and Option Strict can reduce the likelihood of runtime errors via compile time identification of likely issues. See my article on Error Handling in ASP.NET for more information.
  2. Runtime errors: these are bugs � programs that compile successfully but do not behave as expected.

In part I of this article we have already come across setting of the configuration mode of the application in VS.NET and the ability to differentiate between Release and Debug modes, the latter being the default.

Debug mode may be set explicitly within the web.config file via the compilation element as follows:

<compilation debug="true" />

as well as at the Page level via the debug attribute of the Page directive.

Setting Breakpoints and Stepping Through Program Execution

Stepping is the step-by-step execution of a program. This allows the developer to track the logic of the program execution to see where it might be going wrong. As part of this facility you are able to monitor the state of application objects (e.g. variables, database table values, etc.) before and after each step to check whether the program is correctly affecting them.

The steps of the stepping process are definable by the developer. The debug menu of VS.NET provides three options for step execution:

Step Into: executes the code in step mode � if a method call is encountered the program execution steps into the code in step mode.

Step Over: will not execute the next method call in step mode, continuing to the next statement after the method call.

Step Out: if already in a method call will continue through the rest of the method without stepping, returning to step mode when control returns to the calling statement.

You may also break program execution on identified breakpoints which allows you to do further analysis on the program state at that point of execution. Typically, you will run the program to a breakpoint, which is a point prior to that which you have identified for possible concern, and step through the subsequent code to check that the code is working as it should.

As well as adding a breakpoint you can remove or disable it. Disabling has the advantage of leaving the breakpoint for possible subsequent use whilst removing its effect for the moment. When you add a new breakpoint you have a variety of options and facilities at your disposal. The breakpoint window is also accessible via the debug menu from which you may manage your breakpoints, locate the breakpoint in code as well as view the corresponding disassembled code.

I'd suggest at this point you open up a web form which uses some code behind and try setting a few breakpoints, start the page with debugging from the debug menu and try stepping though the code. Or you may prefer to wait for the example of the next section.

Further .NET debugging tools: Watch, Autos, Locals, Me, Immediate, and the Call Stack Windows

As you can see from this list you have a variety of other tools available to you as a VS.NET developer to analyse the program state at the breakpoint, as follows:

Watch

The Watch window allows you to add 'watches' to particularly variables and expression for continuous monitoring. Thus when you set up a watch whenever you return to the IDE while debugging you will see the current value of the variable or expression defined by the watch.

Autos

The autos window (automatically) displays the variables in the current statement and the previous statement.

Locals

Displays the variables local to the current context, i.e. the current method under execution

Me

The Me window allows you to examine members associated with the current object � typically a web form for an ASP.NET application, but not necessarily. It also allows you to change these values.

Immediate

The immediate window allows (immediate) access to the values of variables and expressions while debugging, at the breakpoint.

Call Stack

The Call Stack window shows you the method call stack thus providing information about the path taken by the code to reach its current point of execution.

An Example

Let's run through an example. Put together a quick web form with a textbox of id tbNumber, a button labelled 'Calculate' or similar and another textbox for output named tbfactorial. Add the following code to the button's click event:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  Dim intNumber, intFactorial As Integer
  Try
    intNumber = Convert.ToInt32(tbNumber.Text)
    intFactorial = factorial(intNumber)
    tbfactorial.Text = intFactorial.ToString()
  Catch ex As Exception
    debug.writeline(ex.Message)
  End Try
End Sub

and add code in the same class for the factorial function:

Private Function factorial(ByVal intNumber As Integer) As Integer
  Dim intFac As Integer = 1
  Dim i As Integer
  For i = 2 To intNumber
    intFac = intFac * i
  Next
  Return intFac
End Function

Remembering also to add:

Imports System.Diagnostics

to the codebehind file.

Firstly start the application from the debug menu and see what it does. Try entering textual input and see what happens. Check the content of the output window (view � other windows). You should see the debug information displayed via the try ... catch block when you inputted the textual data.

Set a break point near the start of the factorial function and run the page.

Try the windows of the debug menu to see what they will display. Add a watch window and add a watch for the intFac variable. Step into the code and see how the reported value of the variable changes. Similarly open the locals, auto, me, immediate and call stack windows and see how their contents change. Explore each. Two are worthy of further comment:

In the immediate window prefix variable names / expressions with ? to obtain a response, e.g. ?intFactorial. You may also call functions, e.g. Factorial(intNumber).

In the call stack window the currently executing method is at the top of the stack pointed by a yellow arrow. When this method is exited, the next entry in the stack will be the method receiving the control of execution.

Debugging on exceptions

You can also control the way the VS.NET debugger behaves when it encounters a line of code that throws an exception. This is achieved via the Exceptions dialog box (Debug-Exceptions). This allows specification of the debugger's behaviour for each type of exception defined in the system, including programmer defined exceptions if you so desire. Behaviour is controllable on two levels:

  1. when the exception is thrown
  2. if the exception is not handled

Debugging a running process

Up until this point we have assumed that the application we are running is doing so within the VS.NET environment by starting them within this environment. VS.NET also allows you to debug processes running outside the debugging environment � handy for debugging already deployed applications, e.g. applications in staging environments. This kind of thing often proved problematic with previous versions of VS.

When a web page is served from the web server, the ASP.NET worker process (aspnet_wp.exe) serves the request. To debug a running page you need to attach the VS.NET debugger to the aspnet_wp.exe process running on the web server. Additionally, you need to open the corresponding source files in VS.NET and set your breakpoint at a suitable location. Now when you interact with the already running web page it will break into the debugger whenever the break point is hit.

The actual steps needed to achieve the above are:

  1. Launch the page in Internet Explorer.
  2. VS.NET Tools � Debug Processes. Change the name field to point to the web server specified in 1, making sure you check the 'Show system processes' option. In the available processes list you want to attach to aspnet_wp.exe. Selecting attach will bring up an 'attach to process' dialog box � select the CLR option and click OK.
  3. Open the corresponding source file in VS.NET.

A couple of important points:

  1. Don't debug on production servers � attaching a debugger to an aspnet_wp.exe on a production server will freeze the execution of all other applications / user application instances on that server.
  2. Similarly don't terminate the aspnet_wp.exe process after debugging is complete as it will affect all other applications / users on that server.

Debugging a remote process

This is similar to debugging a running process. The difference is you are effectively debugging on the remote machine. The extra step required is that prior to when selecting a running process from the Processes dialog box you must select the remote machine name from the name list.

Further, before you can debug remotely you must perform a one time configuration of the remote machine where the processes are running achievable via either installing VS.NET on the remote machine or installing the remote components setup on the remote machine (VS.NET setup disk 1).

This will ensure that the machine debug manager (mdm.exe) is on the remote computer. This runs as a background service providing debugging support. The logged in user at time of installation will also be added to the Debug users group � a further requirement for this to work. This process will also configure SQLServer for Stored Procedure debugging if SQLServer exists on the server.

For further information see 'setting up remote debugging' in VS.NET help

Debugging Code in DLL Files

The process of debugging a DLL file for which you have the source code is similar to debugging a web form with one main difference: the code in a DLL cannot be called directly so you need a client (web form) to call it. This makes the typical process as follows:

  1. Launch the web form that uses the members of the DLL.
  2. Launch VS.NET and attach the debugger to the web form. Set a breakpoint where the method in the DLL file is called. Continue with execution.
  3. Execution will break at the breakpoint and you can step into the DLL code from the Debug menu.

Debugging Client-side Scripts

Again this works similarly to web forms with the proviso that client-side debugging only works with IE. You have to enable script debugging in IE (Tools-Internet Options-Advanced and uncheck Disable script debugging in the browsing section).

You can then attach the debugger to the iexplore.exe process displaying the web form. This is only required if you are debugging an already running process. When attaching to the process in the Attach to Process dialog box you must make sure you select the script option.

Debugging SQLServer Stored Procedures

You can even perform debugging of stored procedures in the VS.NET environment and here is a brief overview of how to achieve this:

You need to enable SQLServer debugging for your solution. The option for this is located via Solution-Properties � Configuration properties � Debugging. I'll assume you have a project that uses stored procedures as the interface between data store and web form already. Set a breakpoint in your web form code before you call the stored procedure. In Server Explorer navigate to the stored procedure in question, right click and select edit. Insert a breakpoint in the first line of code.

Run the project; execution will break at the breakpoint in the web form. Select 'step into' until the stored procedure is called and you will be able to step through the stored procedure code as well. Investigate how you can still use the watch and locals windows to examine variables.

This ability is a boon to developers needing to debug complex stored procedures.

Conclusion

I hope the two articles in this series have provided a reasonable introduction to debugging your ASP.NET applications. Part I focused on the support for tracing in.NET and part II on debugging tools and techniques. If there are any aspects of these articles, or any other on DotNetJohn for that matter, that you would like me to look at in further detail email me sullyc-olops@btinternet.com or DotNetJohn.

References

ASP.NET: Tips, Tutorial and Code
Scott Mitchell et al.
Sams

Developing and implementing web applications with VB.Net and VS.Net
Mike Gunderloy
Que

.NET SDK documentation

You may download the test program here.