Diagnostics and Support

So far we have looked at developing and deploying .NET applications. Part of software development is also to specify what the code is expected to do (by means of documentation) and to debug and verify that the code is working the way you expect. The .NET SDK provides many useful tools and mechanisms for these purposes. Let's take a look at some of them.

Tracing

The simplest way to check the behavior of the code is to add some trace statements into the code. The .NET Framework provides a class Debug (namespace System.Diagnostics) that provides many useful static methods to instrument your code. For example, Debug.Write can be used to output a string, as shown in the following code excerpt:

// Project Tracing

public static void Main() {
     Debug.Write("Debug: I am in main");
     ...
}

Debug.Write is a conditional statement; it is included in the source code only if a symbol DEBUG is defined. With the C# compiler, this can be done by specifying –d:DEBUG as a command-line parameter, as shown here:

csc.exe -t:exe -d:DEBUG -out:MyAppDebug.exe MyApp.cs

The output of the Debug statement is captured by a BCL-defined static collection object, Debug.Listeners. By default, this collection object contains just one listener, DefaultTraceListener. This default trace listener outputs to the Windows system debugger (using OutputDebugString Windows API). Most standard debuggers such as the one that comes with Visual Studio .NET can catch this output. When a debug executable is run from Visual Studio .NET, the trace messages can be seen in the Output window in Visual Studio .NET.

You can also catch the output from OutputDebugString using the Debug Monitor (DbMon.exe), a tool that comes with the Windows Platform SDK. The source code (DbMon.c) can be downloaded from [MS-90].


Besides Write, class Debug provides many other useful routines such as WriteLine, Assert, WriteLineIf, and so on. Look into the SDK documentation for more details.

Symbol DEBUG is used only for debug builds and should never be used with builds that will be shipped to the customers. What if you wish to trace execution in a shipping product? The .NET Framework defines yet another class Trace just for this purpose. Trace is identical to Debug in most respects, except that it gets enabled when a symbol TRACE is defined during compilation.

Debug Build Settings

For debug builds, it is a good idea to define both DEBUG and TRACE symbols.


No matter which tracing class you use, you are not limited to use just the default trace listener. You can always create your own TraceListener derived class and add it to Debug.Listeners or Trace.Listeners. As a matter of fact, the framework defines two such classes, TextWriterTraceListener and EventLogTraceListener, that you can use to customize tracing within your application. The former class can be used to redirect tracing to a stream class (such as a file) and the second one can be used to redirect tracing to the Windows event log.

You can also control the amount of tracing information by means of some switches. The SDK documentation explains this in detail.

Using the Debugger

The .NET SDK supplies a console-based tool (CorDbg.exe) and a Windows-based tool (DbgClr.exe) to debug an application. However, the Visual Studio .NET debugger is much more powerful than either of these debuggers and probably would remain the most popular choice of debugger.

No matter which debugger is used, the application being debugged has to be compiled such that it contains debugging information (unless you are good at debugging in hex numbers). This can be done by using the -debug command-line option on the compiler, as shown in the following example (Project Debugging):

csc.exe -t:exe -debug -out:MyAppDebug.exe MyApp.cs

Option -debug does two things:

  1. It creates a programmer's database (PDB) file that maps MSIL instructions to source code lines.

  2. Creating just the PDB file is not enough. We also need a mapping between the MSIL instructions and the native code. Recall that the native code is generated on the fly. The JIT compiler has to be instructed to create the mapping between native code and MSIL. Option -debug causes this to happen by setting an assembly-level attribute called JITTracking.

Note that the JITTracking attribute gets set automatically if you run the program from within the debugger. However, if you attach to an already running process, and if this attribute was not set during compilation, then there is no mapping back to MSIL instructions and therefore to the source code. In this case, the only code that you can see from the debugger is the native language instructions.

To run a program using CorDbg.exe, you can specify the executable name as a command-line parameter, as shown here:

CorDbg.exe MyAppDebug.exe

Once you are in the debugger, you can set breakpoints, examine variables, execute the code to the next breakpoint, and so on, pretty much what you would expect from a standard debugger.

As a bonus, the source code for CorDbg is supplied as an SDK sample. It is a good reference sample to get more insight into how the common language runtime executes a program.

DbgClr.exe is based on work that was being done for the Visual Studio .NET debugger. Although not as powerful as Visual Studio .NET debugger, it is still a decent GUI-based debugger.

Documentation

We all agree that documenting code is as important as developing code, although it is a tedious job.[3] Fortunately, C# provides a simple mechanism for the developers to document their code using XML. Structures, classes, interfaces, methods, events, properties, and so on, can all be documented using the /// commenting style followed by a predefined XML tag. The following code excerpt demonstrates the use of some common tags to document classes and methods (Project Documentation):

[3] Most developers I have worked with do not seem to like documenting code.

/// <summary>This is my main application class</summary>
/// <remarks>
///  This is where a longer comment for my class goes.
/// </remarks>
class MyApp
{
     /// <summary>
     ///  This function greets the specified user
     /// </summary>
     /// <param name="user">The name of the user</param>
     /// <returns>Doesn't return any value</returns>
     public static void Greet(String user) {
       Console.WriteLine("Hello " + user);
     }

     /// <summary>The main entry point</summary>
     public static void Main()
     {
       MyApp.Greet("Jay");
     }
}

Any valid XML tag can be used for documentation. However, some commonly used tags are documented in the SDK under C# Language Features.

The compiler can be directed, using –doc option, to process this source file and produce an XML documentation file. The following command line results in producing MyDoc.xml as the documentation file.

csc.exe -out:MyApp.exe MyApp.cs -doc:MyDoc.xml

The generated XML file can be run through a transformation mechanism that produces the output in the desired format.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.226.105