Friday, August 04, 2006

Get Superman Like X-Ray Vision with New Debug Visualizers

Visualiser Basics

Ok, so if you don't know what a visualiser is or you want to know how to build one, you're in the wrong place. A Google search ought to satisfy your curiosity, or you could try the Dr.Dobb's Portal article, which seems fairly comprehensive. I also highly recommend Frans Bouma's blog : Tips for writing Debugger Visualizers in VS.NET.

If you just want to download my new visualizers and try them yourself, go here.

Why Build New Visualizers ?

To be honest, I've only just woken up to how cool visualizers are. The company I work for has been using Visual Studio 2005 for about two years now (starting with beta 1) to produce two major products. We discovered visualizers early on, and even went to a TechEd session last year that was largely about visualizers. We weren't that impressed though, mostly because the visualizers that come with Visual Studio, while both functional and useful to a point, aren't exactly cool. Since the standard ones aren't particularly interesting and we were busy building our own products, we had little interest in spending time to write our own visualisers. We simply used the ones available and lived with their limitations.

This changed recently, when for about the millionth time, I had to write an XPath query against a piece of foreign Xml. I used the XML visualiser to bring up the Xml during my debug session (I often code in edit and continue mode, if only because I'm too lazy to hit the stop button). Of course the Xml document was quite large and the visualiser didn't load all that quickly, then when it did display I had to get rid of the SP2 security warning at the top of the browser control. At this point I was now able to view the node heirachy and attributes names etc. Cool.

Unfortunately, visualizer dialogs are modal. So having looked at the Xml I was forced to close the visualizer before I started writing my XPath query. Of course I got interrupted, and when I got back to my desk I couldn't remember the Xml structure again. Why, oh why, can't I do something useful with the Xml visualizer like write and test XPath queries using it ? Or search a large document for a particular node/attribute name or value. Even copying & pasting Xml from the standard visualizer doesn't work well, since copying from the browser control includes all of the +/- symbols from it's tree display. Worst of all, you can't use the standard visualizer on most of the Xml or XPath objects (XmlDocument, XPathDocument, XmlNode, XPathNavigator etc.)

The frustrations don't end there. The text visualizer suffers from similar problems, no search, save or print functions (search being the most useful). There is no image visualizer, and both myself and two of my colleagues have had to deal with retrieving images from web services, databases, or modifying images with drawing commands, and an image visualiser that could cope with visualizing strings, streams and images would have been useful in all those situations.

Building the New Visualizers

With my frustration mounting, I searched the web for a new Xml visualizer. There are several around, and they look quite good - except they don't do what I want. All of the Xml visualizers I found display the Xml in some graphical view, which is very pretty and perhaps good for navigating through a document, but not what I need. Some of them also explicitly state they don't work well with large documents. In the end, I decided to write my own Xml visualiser.

I started by first creating the Image Visualiser, figuring it would be the simpler of the two (and it was). I later updated this to support saving the image to disk or copying it to the clipboard.

Now that I knew what I was doing (sort of), I set about creating the Xml Visualiser. This was good practice for me anyway, since I got to try out some globalisation/localisation tools and windows forms controls that I haven't been able to use in my own projects at work for technical reasons. In any case, I now have a visualizer for Xml that will do everything I want and a bit more besides (apply an XSLT and view the result etc). It will even view XmlNode or NodeList objects (it applies a temporary root node to the visualized data so it can be treated as a valid Xml document).

Nothing Is Ever Easy

I was about done at this point, but then realised I had never much liked the UI for the Managed Debug Assistant for Exceptions. It doesn't show the inner exception unless you click on View Details, and even then all the text for the stack trace and so on is shown in a really small font, in a grid cell. This makes it hard to read, as well as copy and paste etc. I decided to make a visualizer for exceptions. This was where I hit my first snag.

I expected I could specify System.Exception as a target for the visualizer, and then visualize any object that inherits from it. Sadly this was not the case. Confusion struck momentarily when I realised that I could specify System.IO.Stream as a target and visualize derived objects. The key seems to be that System.IO.Stream is an abstract class and can't be instantiated, so the system assumes you must want to visualize derived objects. For objects that aren't abstract, the reverse case is applied, only variables of the target type explicitly listed in the
DebuggerVisualizer attribute can be visualized and not derived classes. I've reported this to Microsoft through the Visual Studio Feedback Centre and have suggested they add a boolean parameter to the attribute to specify whether derived types should be allowed. I can only hope it will be fixed in the future. For now, I've given up on the idea of an exception visualizer.

The same problem also limited the usefulness of a collection/list/dictionary visualizer I tried to build, since it also applies to specifying an interface as the target type for visualization.

My second problem was related to error handling. I wanted to protect the user's Visual Studio/debug session from any problems occurring in my visualizer. I didn't need anything too fancy in the way of error handling though so I put a try/catch in all my routines with a simple message box to display any errors that occurred. This was a bad idea inside the VisualizerObjectSource classes, since Visual Studio will timeout if methods in these objects take too long. Too long being determined by Visual Studio, and usually being less than the time the message box was displayed on screen for.

The end result was that everything either crashed in a nasty way or gave you a series of rude error messages that left you with a sour taste in your mouth. Instead, I simply changed this routine to catch and hide the errors, and return an empty VisualizerObjectSource object, which means the visualizer runs without crashing but simply doesn't show any data.

Later when I have more time I might change the code so the error message is placed in a property on the VisualizerObjectSource and then displayed in the visualizer. Since errors shouldn't occur anyway though, I haven't worried too much about it for now.

But Wait... There's More !

I thought I had pretty much covered my bases at this point. I wasn't interested in building a text visualizer since I didn't use the standard version much and all it was really missing was a search option. I figured I could easily get around that by copying and pasting text from the text visualizer into notepad. Of course, that same week I needed to use it several times, got feed-up again, and so I built my own.

This was also a good excuse to try out the new PrintDocument and PrintPreview controls which I hadn't used previously. They're pretty cool, but not very interesting if you have SQL Report Services or Crystal Reports at your disposal.

I was certain I was done now. Turns out I was wrong again. Surprising, I know. I think it happened once in 1984...

One of our projects at work deals heavily with Message Queue. Most of our messages have their contents compressed with Gzip, which means the body/bodystream properties are boring unless they are first decompressed, and it's pretty hard to get a good view of a message object simply using the Debug Tips anyway. We also frequently find, during development, that we'd like to delete just one or two messages from a queue, rather than purge the whole queue. This is something that MSMQ explorer doesn't allow you to do.

I built the MSMQ Message visualizer pretty easily, although it appears a System.Messages.Messsage object isn't serializable, so I had to create a VisualizerObjectSource object and manually pull out the properties I was interested in.

The MSMQ Queue visualizer was a little different. I had the same problem with the queue object not being serializable, but that only took a bit of typing to solve, nothing new there. When I started thinking about the user interface and what I wanted to be able to do with the queue though, I realised I might well want the same features outside of a visualizer (perhaps in a support tool, or a stand-alone exe for use on our test systems that don't have development tools). Therefore, I decided to create a composite control to do most of the work around displaying and managing the queue, and the visualizer dialog just plays host to the control.

The new visualizers have actually made my experience with debugging our MSMQ code a lot more pleasant, although I still haven't added all the features I'd like to either the queue explorer control or the message visualizer. I'm also not entirely happy with the performance of displaying each of the visualizers, and I've had a few issues I can't explain when using them during remote debugging sessions. The extra's can wait for now though, and I'm working on the performance/remote debugging issues.

In any case, having built the visualizers (and been told how cool the Xml one is by one of my colleagues), I've put them up on the web for download. Just make sure you're ok with the license agreement before you use them. It basically says I'm not responsible for anything :)

No comments:

Post a Comment