When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, January 18, 2006

Improved Debugging with Visual Studio 2005's Debugger Visualizers

By Scott Mitchell


Introduction


When debugging a project in Visual Studio .NET 2002/2003, you can view the current values of a variable by simply entering the value into the Watch window, or by hovering your mouse over the variable in the code window. While this approach worked wonderfully for simple types with short and concise values, the user interface was less than ideal for more complex types or lengthy values. For example, if you were working on an application that manipulated the contents of an XML file you might want to examine the XML string at various points in the application. This would be a challenging task if you had XML content that was more than a few dozen characters long, as Visual Studio .NET would format the XML content in one loooooooong line of text. Kind of made it hard to quickly examine the contents of the XML!

Thankfully the debugger experience in Visual Studio 2005 is much better. In DataTips, Visualizers and Viewers Make Debugging .NET Code a Breeze author Morgan Skinner examines DataTips and Visualizers, two of the nice new debugging features. To summarize, DataTips provide a tooltip-like view of the important properties when in break mode, which you can view and modify. Visualizers present an alternate view of an object or variable in a manner that is more specific to the data type.

Visual Studio 2005 ships with four visualizers, a DataSet visualizer, which shows the contents of a DataSet in a grid, and three text-based visualizers: one for text, one for XML, and one for HTML. The screenshot below shows the XML Visualizer in action, which provides a much more readable view of the XML than simply squishing it all on one line.

The Visual Studio 2005 XML Visualizer in action.

What's particularly cool about Visual Studio 2005's debugger visualizers is that the visualizer framework is pluggable. That is, we can create our own custom visualizers and plug them into Visual Studio! In this article we'll look at the basics of debugger visualizers, examine some of the built-in visualizers, look at a few free visualizers developed by various folks in the community, and see how to create our own visualizer! Read on to learn more!

- continued -

Visualizer Basics


When debugging an application, developers are often interested in the value of certain variables. Visual Studio provides a number of windows - Watch, Autos, Locals, and so on - that provide the current values of various variables. However, these windows' display capabilities are very generic, meaning that regardless of the type of variable being examined, the output is roughly the same. However, for certain types of variables there may be a much more intuitive way to display the value. For example, when viewing the value of a string that contains HTML, rather than just showing the raw markup, a developer might be interested in seeing the markup rendered, as it would appear in a browser.

Visualizers allow for a more type-specific view of a variable during the debugging experience. Visualizers apply to certain types - the Text, HTML, and XML Visualizers, for exmample, apply to string variables. When debugging, you can mouse over such a type in the code window or Watch, Locals, or Autos window and see a little magnifying glass appear. Clicking this will display the value of the variable using the selected visualizer. (For types that support multiple visualizers, such as strings, a drop-down list accompanies the magnifying glass and allows you to select which visualizer to use.)

To illustrate use of the visualizers, create a project in Visual Studio 2005 that has a few string variables. In one, put some valid, XML content; in another, put some HTML content; in the third, put a long string. Next, set a breakpoint in the code and then start debugging. In the Watch window at a reference to the three variables that hold the XML, HTML, and long string values. You'll see a magnifying glass along the right side of each string variable's value, as shown below.

The Watch window.

Clicking the magnifying glass will display the selected visualizer. You can choose which visualizer to use by clicking on the little down arrow next to the magnifying glass. In this article's Introduction I showed you the results of the XML Visualizer; below are examples showing the Text and HTML Visualizers.

The Text Visualizer. The HTML Visualizer.

Dissecting the Visualizer Functionality


At the core, a visualizer has two tasks it must fulfill: first, when given an object instance of a particular type it must be able to take that instance and create a user interface displaying details about that object; second, it must contain the plumbing necessary to interact with the Visual Studio debugger. Part of the challenge in creating a visualizer is that the visualizer runs in two different processes: within the Visual Studio debugger as well as within the running program iteself. A visualizer is implemented as an assembly that includes metadata indicating the particular data type the visualizer is designed to work with. When a developer starts debugging in Visual Studio, the environment loads all of the visualizers and determines what data types they can work with. Then, when the developer mouses over a variable in the code window or Locals, Autos, or Watch windows, Visual Studio displays the magnifying glass icon.

Clicking the magnifying glass icon prompts the visualizer to load this data from the program itself and and pass this data to the visualizer program that resides within the debugger in order to display the data on screen. This passing of data from one portion of the visualizer to the other occurs using binary serialization through streams; the end result is that any objects passed between these partitions of the visualizer must be serializable. Once the visualizer running in the debugger is passed the serialized object to display, it is responsible for creating the user interface that shows the object's value. This likely entails creating a Windows Form and populating its controls with values based on the received object's data.

Extending Visual Studio 2005 with Custom Visualizers


While the four built-in visualizers in Visual Studio are nice, what really makes the visualizer concept useful is that it is pluggable. Developers can create their own custom visualizers and register them with Visual Studio, and registration is as easy as copying a DLL file to a particular directory. Due to the pluggability of visualizers, a number of developers in the community have created free visualizers that you can plug into your copy of Visual Studio.

Some free visualizers (many with source code) worth checking out include:

(ASP.NET team lead Scott Guthrie has a more thorough blog post highlighting additional visualizers avaiable from the community.)

Creating a Custom Visualizer


Creating a custom visualizer typically involves creating three related objects:
  1. A "visualizer" class - when the developer clicks the magnifying glass during the debugging session we must somehow reference the corresponding object and display its data in the desired format. The act of getting the object data from the debugger and passing this data to the user interface is the responsibility of this visualizer class. This class extends the DialogDebuggerVisualizer class and provides a Show() method that is responsible for grabbing the data and invoking the user interface. This class also should contain the assembly attribute indicating that visualizer's applicable data type.
  2. A "source" class - the source class's responsibility is to take the object whose magnifying glass was clicked and pass this object information out of the debugger. This class extends the VisualizerObjectSource and provides the GetData(object, Stream) method to provide a serialized version of the object to the visualizer class. Specifically, the GetData() method's first input parameter is the object whose magnifying glass icon was clicked; the second input parameter is the Stream to which the object must be serialized.
  3. A "user interface" - the user interface by which the data will be displayed. Typically this involves creating a Form (or two), adding the appropriate user interface elements (TextBoxes, TreeViews, etc.), and having the visualizer class pass the user interface the serialized data to display.
To illustrate this interaction I've built a rather simple visualizer that is designed to display the server variables. The visualizer is associated with the System.Web.UI.Page class. (You can download this class at the end of this article.)

Let's start by looking at the source class. The GetData() method here starts by casting the first input parameter to a Page object and then dumps the values of the Request.ServerVariables collection to a new NameValueCollection. (I do this deep copy because the Request.NameValueCollection is, underneath the covers, an object of type HttpServerVarsCollection, which is not serializable and therefore can't be ferried from the source class to the visualizer class. The NameValueCollection is serializable, however, so after dumping the contents from Request.NameValueCollection to a local NameValueCollection, I then serialize the contents to the Stream that was passed-in as the second input parameter:

public override void GetData(object target, System.IO.Stream outgoingData)
{
    if (target != null && target is Page)
    {
        Page p = (Page)target;

        // Dump the contents from Request.ServerVariables to
        // a local NameValueCollection b/c Request.ServerVariables
        // is NOT serializable...
        NameValueCollection nvc = new NameValueCollection();
        foreach (string key in p.Request.ServerVariables)
            nvc.Add(key, p.Request.ServerVariables[key]);

        // Serialize nvc to the outgoingData Stream
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(outgoingData, nvc);
    }
}

Next, in the visualizer class's Show() method we deserialize the data from the GetData() method and create the user interface. This is accomplished with the following code:

protected override void Show(IDialogVisualizerService windowService, 
                             IVisualizerObjectProvider objectProvider)
{
    // Deserialize the Stream returned by GetData() into a NameValueCollection
    NameValueCollection vars = null;
    using (Stream dataStream = objectProvider.GetData())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        vars = formatter.Deserialize(dataStream) as NameValueCollection;
    }

	// Create the user interface form, passing in the NameValueCollection
    using (VisualizerForm displayForm = new VisualizerForm())
    {
        displayForm.Visualize(vars);
        windowService.ShowDialog(displayForm);
    }
}

The VisualizerForm class is a Windows Form that contains a ListView control. The VisualizerForm class's Visualize(NameValueCollection) method (which I wrote), takes the passed-in NameValueCollection object and dumps its contents to the ListView.

Also included in the visualizer class is the DebuggerVisualizer attribute, which wires up the visualizer to the System.Web.UI.Page data type:

[assembly: DebuggerVisualizer(
    typeof(skmVisualizers.ServerVariables.Visualizer),
    typeof(skmVisualizers.ServerVariables.ServerVariablesControlSource),
    Target = typeof(System.Web.UI.Page),
    Description = "Visualize the page's server variables.")]

Deploying and Testing the Custom Visualizer


Once you've successfully built the custom visualizer, deployment is a breeze. Simply copy the assembly (the DLL file) to the My Documents\Visual Studio 2005\Visualizers folder. That's it! To test the visualizer out, open up Visual Studio 2005, create a new website project and set a breakpoint in the code. Next, start the debugger. When you hit the breakpoint, type into the Watch window Page (or this in C# or Me in VB). You should see a little magnifying glass icon in the Watch window. Click on this and you should see the dialog box shown below. If you select a particular item from the ListView, you'll be shown a detailed view.

The Server Variables visualizer.

The details of a particular server variable.

One of the pains of developing visualizers is testing/debugging the visualizer. The only sure-fire way to ensure that you have the full debugger experience is to build your visualizer assembly, manually copy it to the Visual Studio 2005 Visualizers directory, launch VS, and start debugging. If you find a mistake or want to make a change you need to stop debugging, close Visual Studio, make the change to the visualizer, recompile, recopy the file to the Visualizers directory, relaunch VS, and return to debugging. Ick.

There is another, more efficient way that you can use that actually allows you to step into the visualizer code through the debugger. This technique involves creating a stand-alone Console Application, as discussed in Creating a Debugger Visualizer Using Visual Studio 2005 Beta 2. The only downside is that since you are not really running the application, you have to simulate the serialized object from the source class, which means you'll be missing out on request-specific information that you would have when actually debugging. (This is more of an issue when working with ASP.NET instrinsic controls, like the Page class.)

Conclusion


Visual Studio 2005 has improved the developer's experience in many ways, one of which has been an improved debugging experience. One of the cool new debugging features in Visual Studio 2005 is the debugger visualizers, which provide a custom way to view specific data types. Visual Studio ships with four built-in visualizers, but there are plenty of community-created visualizers and the architecture exists to easily create our own custom visualizers. In this article we looked at the visualizer model, three of the four built-in visualizers, a number of community-created visualizers, and even saw how to create our own visualizer.

Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the custom visualizer code


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article