PAGES

3

Apr 11

Write Your Own Debugging Visualizer



Originally posted on Mike Frank’s blog Listen…You Smell Something

Have you ever been stepping through a program and tried to inspect an object only to find it has an internal structure that make it very difficult to really see what is going on in there? I recently ran into a third party object that was causing me that problem over and over so I decided to do something about it. I wrote my own debugging visualizer to take the object and put it into a format that is easy to read. I was surprised how easy it is to do, so lets create one.

The Setup

The object I was struggling with was storing collections of name/value pairs internally in 2 different collections. So I’d have to find the key I’m interested in, note the index and find the corresponding index in the values collection. It was actually worse than this since the collections were also hierarchical. Ouch. So I put together a simple class that demonstrates this called WeirdCollection. It looks like this:

 
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;

namespace WeirdCollection
{
    [Serializable]
    public class WeirdCollection : IEnumerable
    {
        private readonly StringCollection _keys;
        private readonly StringCollection _values;

        public WeirdCollection()
        {
            _keys = new StringCollection();
            _values = new StringCollection();
        }

        public void Add(string key, string value)
        {
            _keys.Add(key);
            _values.Add(value);
        }

        public CollectionObject this[int index]
        {
            get
            {
                return new CollectionObject
                           {
                    Key = _keys[index],
                    Value = _values[index]
                };
            }
        }

        public int COUNT() as Computed
        {
            return _keys.Count;
        }

        #region Implementation of IEnumerable

        public IEnumerator GetEnumerator()
        {
            return _keys.Cast<string>().Select((t, i) => new CollectionObject { Key = t, Value = _values[i] }).GetEnumerator();
        }

        #endregion
    }
    public class CollectionObject
    {
        public string Key { get; set; }
        public string Value { get; set; }
    }
}

I also put together a little console application that creates a WeirdCollection and writes it back out to the screen:

 
using System;
using WeirdCollection;

namespace DebugMe
{
    class Program
    {
        static void Main()
        {
            var col = new WeirdCollection.WeirdCollection
                          {
                              {"a", "Alpha"},
                              {"b", "Beta"},
                              {"c", "Charlie"},
                              {"d", "Delta"}
                          };

            foreach (CollectionObject collectionObject in col)
            {
                Console.WriteLine("{0} - {1}", collectionObject.Key, collectionObject.Value);
            }

            Console.ReadLine();
        }
    }
}

So when we run this and put a breakpoint after the collection is populated it looks like this when inspected:

QuickWatch Window

So you can see that the keys and values are split and if they had more than a few values they would be a pain to inspect.

Visualizer Background

A Visual Studio Debugger Visualizer is a couple of classes that inherit from classes in the Microsoft.VisualStudio.DebuggerVisualizers namespace and override some of their methods. First the Debuggee side that inherits from VisualizerObjectSource. This is the piece of the visualizer that runs in the process with your program. It’s job is to serialize the object to be sent to the visualizer and apply updates when it is sent back. (I’m not going to cover updates in this post since I haven’t really needed them yet) 

Second is the Debugger side of the visualizer that inherits from DialogDebuggerVisualizer. This is the piece that takes the object and displays it in a dialog or form that you write. The method you override here is called Show and is designed to show a WindowsForms dialog, control or CommonDialog. Eww. So I’m going to show a WPF form instead. Still easy.

Our Visualizer Debugger Side

First we will write the debugger side and use the built in debuggee side. To do this create a new Class Library project and call it WeirdCollectionVisualizer. Add a reference to Microsoft.VisualStudio.DebuggerVisualizers, as well as PresentationCore, PresentationBase and WindowsBase for the WPF. Also need a reference to our WeirdCollection class since this is what we want to visualize. Also add a class called WeirdCollectionVisualizer and a Visualizer.xaml. My project window:

Project Window

So now the code. First the WPF Window. I kept it simple and will assign the DataContext to a Dictionary<string,string> (you’ll see) to make things even easier. The Xaml file:

<Window x:Class="WeirdCollectionVisualizer.Visualizer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             Height="234" Width="163" Title="Profile Visualizer">
    <StackPanel>
        <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=Key}" />
                        <TextBlock Text=" - " />
                        <TextBlock Text="{Binding Path=Value}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>

        </ListBox>
        <Button Content="Ok" IsDefault="True" Click="OkClick" />
    </StackPanel>
</Window>

And the code behind:

 
using System.Windows;

namespace WeirdCollectionVisualizer
{
    /// <summary>
    /// Interaction logic for ProfileVisualizer.xaml
    /// </summary>
    public partial class Visualizer
    {
        public Visualizer()
        {
            InitializeComponent();
        }

        private void OkClick(object sender, RoutedEventArgs e)
        {
            Close();
        }
    }
}

Next up is the visualizer itself. Lets get the code out here and then go over it:

 
using System.Diagnostics;
using System.Linq;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System;
using WeirdCollection;

[assembly: DebuggerVisualizer(
    typeof(WeirdCollectionVisualizer.WeirdCollectionVisualizer),
    typeof(VisualizerObjectSource),
    Target = typeof(WeirdCollection.WeirdCollection),
    Description = "Weird Collection Visualizer")]
namespace WeirdCollectionVisualizer
{
    /// <summary>
    /// A Visualizer for WeirdCollection.  
    /// </summary>
    public class WeirdCollectionVisualizer : DialogDebuggerVisualizer
    {
        protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
        {
            if (objectProvider == null)
                throw new ArgumentNullException("objectProvider");

            WeirdCollection.WeirdCollection wc = (WeirdCollection.WeirdCollection)objectProvider.GetObject();
            
            var win = new Visualizer();
            win.DataContext = wc.Cast<CollectionObject>().ToDictionary(item => item.Key, item => item.Value);
            win.ShowDialog();
        }

        public static void TestShowVisualizer(object objectToVisualize)
        {
            VisualizerDevelopmentHost visualizerHost = new VisualizerDevelopmentHost(objectToVisualize, typeof(WeirdCollectionVisualizer));
            visualizerHost.ShowVisualizer();
        }
    }
}

The first interesting bit is in lines 7-11. This attribute is how you tell Visual Studio that there are classe(s) in the namespace that are involved in debugging. The first 2 areguments are telling it what classes are implementing the Debugger and Debuggee sides of the process. In this case we are saying that WeidCollectionVisualizer.WeirdCollectionVisualizer is the debugger side and the VisualizerObjectSource class from Microsoft.VisualStudio.DebuggerVisualizers will be handling the Debuggee side. The thirs argument says the the class that we want to visualize is WeirdCollection.WeirdCollection. The last argument is the string that will display on the screen when we use the visualizer dropdown during the debugging process. Like so:

Inspect Variable

Next interesting bit is the class definition on line 17. The class inherits from DialogDebuggerVisualizer and must be the class we said would handle the Debugger side in line 8.

Next we override the Show method. This is where all our work is done. There are 2 arguments passed in but we are going to ignore the first one since it pertains to using Windows Forms and we are going to use WPF. The IVisualizerObjecrProvider argument has a couple of methods on it that we might need. The first is GetObject() (used in line 24). This will give you the object to be visualized. The second is GetData() (not used in code above). GetData() will give you a Stream with which you can deserialize the object to visualize. So Show is pretty simple, just make sure we have an object, get it and cast to proper type, create a new instance of our WPF form, set the DataContext and show it as a dialog. Line 27 is alittle bit on Linq fun to turn the ugly collection into a Dictionary<string,string> which is easily bound and shown in WPF.

That’s it. The last method there is just useful for testing and debugging when things get complicated.

Deploying

Deploying is really quite simple as well. Compile the class and copy it to <User Dir>/DocumentsVisual Studio 2010Visualizers. Visual Studio will recognize it as a visualizer targeting WeirdCollection. When you try to inspect a variable of type WeirdCollection in the debugger you will now get the little magnifying glass with a drop down arrow next to it. Click the magnifying glass and our visualizer will launch:

Locals Window

Visualizer

Conclusion

As you can see Debugging Visualizers are actually pretty easy to write and allow you to customize your debugging experience. Obviously this has been a pretty short introduction but in a lot of cases you won’t need much more. If you do there are a lots of examples and samples around the web. For example: Zeeshan Amjad has an excellent article on The Code Project, MSDN has a beginning walkthrough, to name a couple. If you are interested in just how far you can take these concepts check out Mole 2010. It is a Debugging Visualizer on steroids, crack and some weird alien stuff that makes things awesome.

Source code for this post can be found here.

1 comment , permalink


Tagged ,