Debugging Basics


A typical scenario for a developer writing an application today is to start building a screen or form and build up the code that surrounds it. In addition, the developer may rely on a framework or a few building blocks that provide added functionality. The application may also communicate with a services layer and most definitely a database. Even the most typical applications have a lot of moving parts. These moving parts make the task of finding and eliminating errors in the code all the more complex. The tools that help you track down and purge errors from your code not only have to keep up with this complexity, but also must ease the effort involved with the debugging process. In the following sections, we will cover how a developer would use the tools built into Visual Studio 2005 to debug a typical development scenario.

The Scenario

We want to define an application scenario that we can use to both introduce the basics of debugging as well as function as a base for us to build on throughout the chapter when demonstrating the many features of the debugging tools. In this scenario, imagine you are writing a web page that allows customers to view and edit their profiles. This screen offers new functionality to a larger, existing application. The following are some of the conditions that surround this application scenario:

  • The customers' profiles are stored in a SQL 2005 database.

  • A data access library abstracts access to the database.

  • A web service provides the customers' profile information.

Your task is to write this page using the web service to return customers' profiles and write users' changes to their profiles back to the database using the data access library. The application you will be debugging in this scenario is written in C#. However, the debugging tools in Visual Studio are equally applicable to both C# and Visual Basic. That is, everything we discuss here applies to both languages unless specified as otherwise.

The Many Phases of Debugging

Nearly every time developers open the IDE, they are in some way debugging their code. The line between debugging and writing code, in fact, is becoming more and more blurred. For example, the code editor helps eliminate errors in your code as you write it. It highlights items where errors are present and allows you to fix them. You are then both writing and debugging simultaneously.

In addition, the compiler acts as another debugging tool. The first time you click the Run button, the compiler checks your code and reports a list of errors for you to fix prior to continuing. This is debugging. The steps or phases of the debugging process can be broken into the following:

  • Coding The editor helps you by pointing out issues and possible resolutions.

  • Compiling The compiler checks your code and reports errors prior to continuing.

  • Self-checking You run the application in debug mode and step through screens and code to verify functionality.

  • Unit testing You write and run unit tests to check your application.

  • Responding to issues When an issue has been logged against the code, you must re-create and debug a specific scenario.

In this chapter, we will concentrate on two of these phases: self-checking and responding to issues. These are the two phases in which developers will get the most use of the debugging tools built into Visual Studio. We will therefore assume that the code is written and compiles. Let's start by looking at how to self-check the code.

Debugging the Application (Self-Checking)

In this scenario, you have just started writing a web page to edit a customer's profile. Assume that you've laid out the page, connected to the profile web service, and have written the code to save a user's profile to the database. You now need to start self-checking your work to make sure everything operates as you expect.

The first step is to start your application in debug mode. This will allow you to break into your code if an error occurs. In development, this is typically your default setting. You invoke debug mode by clicking the Run button (the green arrow on the Debug toolbar), making sure your configuration is also set to Debug (the default). Figure 9.1 shows the sample application about to be run in debug mode for the first time.

Figure 9.1. Starting the debugger.


Enabling Debugging on a Website

This example is a web application. As such, it requires you to set up debugging on server-side code whose errors and information are output to a remote client. Of course, you are developing on a single development machine. However, sometimes you may have to debug a process on a test server.

In either case, you have to enable debugging through the configuration file (web.config) for your application. Visual Studio will actually initially prompt you to add a config file and enable debugging. Figure 9.2 shows this prompt. Clicking the OK button adds the configuration file to the application and starts the debugging session.

Figure 9.2. Allowing Visual Studio to enable debugging.


Note

It is important that you turn off debugging prior to deploying to production. Having debugging enabled in a production environment is a security risk. With debugging enabled, ASP.NET writes the details of your errors to a web page. These details provide valuable clues to would-be hackers about how your application is put together. In some instances, the error could include user credentials that are being used to access secured resources.


To turn off debug mode, you must edit the web configuration file. Specifically, you edit the Compilation element under the system.web node. You set debug equal to false (as in off). The following is an example of the XML:

<system.web>   <compilation debug="true"/>     ... </system.web>


Starting in Debug Mode

The most typical scenario for starting a debug session is just clicking the Run button on the toolbar. This will compile the application and bring up the initial form or page. You also have the option to start without debugging. This capability is useful if you intend to attach to a running process or simply want to run through the application as a user might see it (without breaking into the IDE).

You can also start by stepping into code, line-by-line. This approach is useful if you want to see all of your code as it executes (rather than just errors). You might desire this if you are getting some unexpected behavior. Stepping line-by-line gives you an exact understanding of what is going on with your code (rather than just your assumed understanding).

Stepping into code on a web form is typically done by first opening the main source. You then right-click and select the Run To Cursor option from the shortcut menu. Figure 9.3 shows an example. This command tells Visual Studio to run the application until it gets to this point. At that time, the IDE will open into debug mode, where you can step through each line of code (or continue and so on).

Figure 9.3. After selecting Run to Cursor, you can start debugging.


Breaking on an Error

Not everything you find in debug mode is an error that results in a break in the code. Often, issues arise just because you're looking at the behavior of the application. For example, a control could be out of place, the tab order could be wrong, and so on. For these items, you still have to rely on your eyes. The debugging tools in Visual Studio help you respond to hard errors in your code.

By default, when unhandled exceptions occur in your code, the debugger will break execution and bring up the IDE with the offending code highlighted. The key in that sentence is "unhandled exceptions." They represent places in your code where you do not have try-catch blocks to manage an exception. This is typically a good default setting. However, you often need to see handled exceptions as well.

Fortunately, the errors that result in a break in the IDE are a configurable set. For example, you may handle a specific exception in your code and not want to be dumped to the IDE every time it occurs. Rather, you want to be notified only of those especially exceptional conditions. The Exceptions dialog box allows you to manage the set of exceptions you're concerned with. You access this dialog box by choosing Debug, Exceptions (or pressing Ctrl+D, E). Figure 9.4 shows the dialog box.

Figure 9.4. Determining where Visual Studio breaks.


In the Exceptions dialog box, the various exceptions are categorized for easy access (there is also a Find feature). The two columns of check boxes are of primary interest: one for Thrown and one for User-unhandled. Notice that, by default, the setting for all exceptions in the .NET Framework is User-unhandled. This indicates that the debugger should break execution only when a given exception is thrown and it is not handled by your code.

Adding Thrown to the mix will tell the debugger to break execution even if you have code to handle the exception. The debugger will react by breaking on the line of the exception, before your handler is called.

For the most part, you would simply toggle Thrown at the CLR level. You probably do not need to get more granular, but you can if you need to. However, doing so often results in confusion.

Debugging an Error

The first step in debugging your application is to click that Run button. You are then in debug mode. As it happens, the sample application throws an exception upon the initial run. The debugger responds by breaking into the code and showing the offending line. Figure 9.5 shows a typical view of the editor when it breaks on an error.

Figure 9.5. The debugger breaking execution.


There are a few items to point out about the standard debug session shown in Figure 9.5. First, Visual Studio has highlighted the line on which the error was thrown. You can see this clearly by the arrow and the highlighted text.

Next, notice the window in the upper right of the image. This is the Exception Assistant, which is new to Visual Studio 2005. It provides details on the exception and offers tips for troubleshooting and fixing the given issue. From this window, you can access a few actions, including searching online help for more information on the exception.

At the bottom of the screen are a few additional helpful windows. The Locals window on the left automatically shows the value assigned to all local variables in the code where the exception was thrown. This gives you easy access to key information that might be contributing to the issue. Notice that to the right of this window is a tab called Watch 1. This is a watch window; it keeps track of any custom watch scenarios you set up (more on this later).

The window on the bottom right of the screen is the Call Stack. It shows the order in which various components of your application were called. You can look at the Call Stack to find out how you got to where you are. You can also use it to navigate to any code referenced in the stack. Finally, the tab next to this gives you access to the Immediate window. It allows you to type in code commands and get the results in the editor (more on this to come).

Attaching to the Web Service

After you examine your error, you can see it is being thrown inside the web service process. Unfortunately, the code called by the web service is being run in a separate process than the one you are debugging. When you debug an application, you debug (or shadow) a running process such as an executable (.exe).

To debug code in the web service process, you must both have the source code and attach to the executing process. In this case, all the code for the running application is in the solution. Therefore, you need to attach to the process.

Attaching to the process will enable you to debug code in libraries called by the web service. However, it will not, by default, enable you to debug the web service itself. The reason is that you have not enabled debugging for the web service. Recall Figure 9.2. Here, you turned on debugging for the web application. You need to do the same thing for the web service if you intend to step through code in the web service. You would do so by adding a web.config file to the site and setting the debug attribute to TRue.

In this case, however, do not end the debug session. You can see that the error is in code contained in a library that is called by the web service, and not the web service itself. Therefore, you simply attach to the web service process and debug code in the DataAccessLib project. To attach to the web service process, you choose the Attach to Process option from the Debug menu. This brings up the dialog box shown in Figure 9.6.

Figure 9.6. Attaching to a process.


In Figure 9.6 notice that the currently attached process is grayed out. This is a visual indicator that you are already attached to the web server running the UI. Beneath this, you see the web service process. To attach the debug session to this process, you simply highlight it and click the Attach button. You are now debugging both processes and can therefore set a breakpoint where the error might be occurring.

Note

If debugging is enabled on both the website and web service applications, Visual Studio still attaches only to the startup project's process. Therefore, if you want to debug code in the web service, you still need to attach to that process (in addition to enabling debugging).


Tip

If you have set a web reference to a web service in your solution and then you enable debugging in that web service, you may get errors from Visual Studio. These errors indicate that the remote server is now rejecting your connection. Unfortunately, the only way around this problem seems to be to delete the web reference and re-add it. If debugging was enabled in your web service prior to setting the web reference, you should be okay.


Setting the Breakpoint

To get the debugger to break into your code when it reaches a specific line, you set a breakpoint on that line. You do so by clicking on the indicator bar for the given line. Alternatively, you can right-click on the line and choose Insert Breakpoint from the Breakpoint context menu. In the example, the error may be coming from the code that gets the customer data from the database. Therefore, you need to navigate to the DataAccessLib project, open the Customer.cs file, and set a breakpoint, as shown in Figure 9.7.

Figure 9.7. Setting a breakpoint.


Continuing the Debugging

After you've navigated off the executing code during a debug session, it can often be hard to find your way back. The line that was executing could be buried in any one of the open code windows. Thankfully, you can use the Show Next Statement button (yellow arrow icon) on the Debug toolbar to take you back. This will return you to the line that was executing when the debugger broke.

In the example, rerun the call to the web service so you can now hit your breakpoint and step through the code. To do so, you must move the current execution point in the code. This can be accomplished by right-clicking the line where you want execution to start (or rerun) and selecting Set Next Statement from the context menu. Figure 9.8 shows this menu option.

Figure 9.8. The Set Next Statement option.


Now that you have backed up the execution point, you are ready to continue the debugging. You can do this by clicking the Run button again. This is essentially indicating you are done with the break and want to continue execution.

Stepping to Find the Error

In the example, the debugger will break execution as soon as it hits the breakpoint in the web service. This will allow you to step through the code. To step line-by-line through the code, you can click the Step Into button on the Debug toolbar or press the F11 function key. This will execute the code one line at a time, allowing you to view both execution flow as well as the state of the application as code executes. Doing so with the example allows you to see the error. It seems that an instance of the DataSet object was not set prior to your trying to fill it.

In most scenarios, you can make this fix during the debug session and continue stepping through or running the code. Unfortunately, in this example you cannot make the change while debugging. You cannot invoke Edit and Continue with an attached process. Figure 9.9 shows the message you get when you try.

Figure 9.9. Edit and Continue error with an attached process.


So instead of using Edit and Continue, you can bookmark the line where you want to make the change using the Text Editor toolbar. You then click the Stop button on the Debug toolbar to stop the debug session. You can now make your change.

To continue through self-checking, you would next restart the debugging process. However, prior to this, you may want to clear the breakpoint you had set. To do so, select the Breakpoints toolbar item. This brings up the Breakpoints window, as shown in Figure 9.10. From this window you can view all breakpoints in the application. Here, you select and clear the breakpoint by clicking the Delete button from the Breakpoint toolbar. Finally, you click the Run button to continue the debug, self-check session.

Figure 9.10. Breakpoints window.


Debugging Basics Summary

You have now set up your scenario and debugged your first error. This example was meant to introduce you to the basics of doing debugging in Visual Studio 2005. If you are familiar with prior IDE versions, you probably noticed a lot of similarities. Walking through the scenario showed the many tools inside the debugging environment, including the Debug toolbar and menu, the Breakpoints window, the watch window, and so on. Now that you have a grasp of the basics, in the next section we intend to explore these debug elements in greater detail.




Microsoft Visual Studio 2005 Unleashed
Microsoft Visual Studio 2005 Unleashed
ISBN: 0672328194
EAN: 2147483647
Year: 2006
Pages: 195

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net