Sunday, November 06, 2005 - Posts

Debugger Visualizers (for lazy people)

Last Wednesday as part of my contribution to a presentation at a meeting of our local .NET User Group, I gave a brief demonstration of Debugger Visualizers.
I should get one thing out of the way before I start: since I am not of the American persuasion I favour "-ise" over "-ize", so while I'll use the word "visualizer" to refer to the actual object under discussion, don't be surprised/shocked/horrified by the fact that I spell the verb referring to the activity in question "visualise"  (and yes, in general terms, I would spell the name of something that performs that activity "visualiser").  It's just one of those things.
So anyway...visualizers, for those who have not yet had the pleasure of their acquaintance are a feature of Visual Studio 2005 that allows you, when debugging, to see certain types of data presented in a useful human-friendly form. Not all datatypes have an associated visualizer (more on that later), but for those that do a magnifying glass and down arrow (expanding to a list of applicable visualizers) will be displayed next to their associated datatips and watch list entries in a debugging session. By default, for string data you can choose a Text Visualizer, XML Visualizer or HTML Visualizer, and for DataSets, DataTables and DataViews there is a corresponding visualizer that displays their contents in a tabular format (complete with column headings).
Anyone who's had to debug a DataSet (and who hasn't?) will appreciate the time this saves.
The XML Visualizer I mentioned earlier formats an XML string in the same way as IE (complete with the ability to collapse and expand levels) - once again that's a big improvement over trying to debug XML as a flat string complete with formatting characters displayed in a DataTip.

One important matter I didn't cover on Wednesday was how to write a custom visualizer for a type not covered by one of those provided out of the box. The reason I didn't cover it then was that at that stage I hadn't successfully written any, but now that I have I'm going to share what I've learned with you lucky people.
First of all, I suggest you all go away and read the excellent article by Julia Lerman that was published in the March/April 2005 edition of Code Magazine. That article goes into considerable detail and provides lots of useful illustrations.

I did say this post was about visualisers for lazy people, and to that end I'm going to briefly describe how to create a custom visualizer using the new project item that has been provided for the purpose in Visual Studio 2005.
I should also get one thing out of the way before I start: you can obviously create visualizers either for existing types for which none exist, or for your own types. In the latter case you should remember to mark the type as serialisable (using the Serializable attribute, as fate would have it). Types to be visualised are required to be serialisable because a copy of the object is actually streamed to the visualizer, which runs in a separate process from the debugging session.

First, create a Class Library project and delete the default Class1.cs file (or Class1.vb if you prefer VB.NET...I haven't checked which of the other language options are currently supported). Now select "Add New Item"...One of the options you should see (I'm sorry, but I don't think this or the visualizer feature in general, is available in the Express editions) is "Debugger Visualizer". Select that option and give the file an appropriate name (such as for the sake of argument "StuffVisualizer.cs"). 
You will notice that the appropriate assembly reference is automatically added to your project, and the visualizer source file contains as you would expect skeleton code for a vizualizer, as well as a number of TODO items.
The default implementation of the Show method retrieves the serialised object and casts it to object. A vanilla Form is then instantiated, its Text property is initialised with the result of the object's ToString() method, and the form is displayed.


It doesn't actually take much to modify this code to be more useful for your purposes.   
To begin with, define a custom form to display the type in which you are interested - obviously the UI will depend on the object and its properties (in the sample code I am visualising an Image, so my form just uses a PictureBox as its UI). You can either pass the object in the form's constructor or define a suitable public property (should you be feeling a bit of anti-constructor snobbery). Before doing this you will of course have to obtain the object in question: in the sort of simple case we're addressing here all you have to do is replace the instantiation of and casting to a generic object with the specific type you want to visualise.
      In order to identify the visualizer as being able to visualise the type in question, the first TODO entry advises adding a DebuggerVisualizer attribute to the definition of the type in question (obviously not something you can do for a pre-existing type). However, it's possible to add a form of the attribute to the visualizer itself, which I personally think is a much better idea even when you have the choice (unless I later find a problem with that, but I don't expect to). Look at the ImageVisualizer class in the accompanying download to see how this work.
For testing your visualizer a static method is helpfully provided (see the help documentation for instructions on using this: really all you have to do is call it from a test project with the object to be visualised passed as a parameter - I've included an example of this in the ImageVisualiserTest project).

Lastly, you have to make your visualizer available to Visual Studio: Create a Visualizers folder under "My Documents\Visual Studio 2005", and simply drop the Release mode version of your visualizer dll into it. The next time you start the debugger it will be listed as one of the available visualizers for the associated type (note that this only makes the visualizer available to you - you can make it available to all users of the machine by adding it to Install path\MICROSOFT 8\Common7\Packages\Debugger\Visualizers. Personally, I prefer not to).