Search
Monday, April 21, 2014 ..:: Home ::.. Register  Login
   Calendar  
     
  
   Search  
     
  
   Blogroll  
     
  
   Disclosure  
All blog entries are the opinions of the author and do not necessarily reflect the opinions of their employer. All the code presented is for explanation and demonstration purposes only. Any damages incurred to your site and/or data are not the responsibility of the author. Every effort is taken to ensure the code properly compiles, however sometimes there are some hiccups and you might be required to do your own debugging.
     
  
   TechTidBits (Blog)  

Visual Studio Debugger Visualizers (Take Three)

Sep 28

Written by:
Tuesday, September 28, 2010 9:11 PM  RssIcon

DataRow Debugger VisualizerIf you are doing DB development, I'm sure you have come to love Visual Studio's DataTable and DataSet debugger visualizer, but have you asked why isn't there one for DataRow and DataRow[]?  Well I did, read on for part of a solution and part of an explanation for the other part.

DataRow Debugger VisualizerIn a previous blog Visual Studio Debugger Visualizers (Take Two), I updated an image debugger visualizer for Visual Studio 2010.  That got Shane and I thinking, wouldn't it be GREAT if you could debug into a DataRow, even a DataRow[]?!  I've been wanting to do that for quite some time, and ironically so did Shane.  It's tiring having to always debug into an ItemArray isn't it?  PITA if you ask me!

DataRow default debugger

HHHHMMMMM can't be THAT hard I thought right?  hhhmmm then I found this link on MSDN.

MSDN says no can do

OH SNAP!!!!!!!!!!  You can't write a custom debugger visualizer for object or Array?  Ok, object is cool, but what do the mean by Array?  Do they mean the specific Array class?  Or do they mean ANY array?  No where does it say anything about other non-serializable types, so somehow I just assumed I could write one for a DataRow AND a DataRow[] (that's NOT an Array after all right? LOL DOH!).

My first attempt at doing this resulted in DataRow being unserializable error messages.  More specifically, RemoteObjectSourceException was unhandled by user code Type 'System.Data.Row' in Assembly 'System.Data, Version=4.0.0.0, Culture=neutral, PublicToken=b77a5c561934e089' is not marked as serializable.  hhhmm if it's NOT serializable, how the heck DO you serialize it to see it?

DataRow not serializable errors

Ah man, by this time, I'd already spent a good three hours trying things out and not having much luck getting them to work (using the image debugger visualizer as a template).  But THEN, BINGO!!!!!!!!!  I found another blog about how to customize the data coming OUT of the object being debugged and INTO Visual Studio's debugging system.  BEAUTIFUL!!!!

MSDN: DialogDebuggerVisualizer naging about serializable

stackoverflow: Debugger Visualizer and "Type is not marked as serializable"

The meat of those forum postings is about Visual Studio not being able to serialize something and leads to creating a custom class to tell Visual Studio how to "parse" your non-serializable object out into something which is serializable and consumable by the debugging system.  Beaut!  Ironic, MOST of the debugger visualizer code samples I'm finding are about showing images....makes me wonder why MS doesn't have one of their own included in Visual Studio?

The gory details means you have to decorate your namespace with this attribute

[assembly: DebuggerVisualizer( typeof( PCHenry.VisualStudio.Utilities.DebuggerVisualizers.DataRowDebuggerVisualizer ),
  typeof( PCHenry.VisualStudio.Utilities.DebuggerVisualizers.DataRowVisualizerObjectSource ),
  Target = typeof( DataRow ),
  Description = "PCHenry DataRow Debugger Visualizer" )]

The main part here is the Target = typeof( DataRow ), that tells VS what object you want it to act upon when it sees it.  In this case DataRow. 

Next you need to create a class which tells VS how to serve up the DataRow.  If you don't you'll get a bunch of "hey doofus, can't you read the MSDN docs, DataRow's not serializable, you can't do this" type of error messages at runtime.  DOH!

  public class DataRowVisualizerObjectSource : VisualizerObjectSource
  {
    public override void GetData( object target, System.IO.Stream outgoingData )
    {
      if( target != null && target is DataRow )
      {
        DataRow row = target as DataRow;
        DataTable table;

        if( row.Table == null )
        {
          table = new DataTable( "DataRowDebuggerTableObjectSource" );

          for( int i = 0; i < row.ItemArray.Length; i++ )
          {
            table.Columns.Add( "Col" + i.ToString(), typeof( string ) );
          }
        }
        else
        {
          table = row.Table.Clone();
        }

        table.LoadDataRow( row.ItemArray, true );

        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize( outgoingData, table );
      }
    }

The meat here is create a DataTable which I know is serializable as my data mule for the debugging system.  Now, I don't really want to create a BRAND SPANKING new DataTable if I can help it, and thankfully, DataRow has a .Table property which I can access to get schema information to use.  Therefore when you're debugging your DataRow, you're seeing a pretty close replica of the real deal.  However, there COULD be a slim chance you won't be able to get the shema data, so juuuuuust in case, create as close a copy of the DataTable as you can by going through the DataColumns.

Ok, now you have a DataTable being passed OUT to VS, now what?  Well, you have to create another class to parse out that outgoing DataTable and look at it.  This comes in two parts.  First is the code to decipher/deserialize the DataTable.

  public class DataRowDebuggerVisualizer : DialogDebuggerVisualizer
  {
    protected override void Show( IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider )
    {

      DataTable table = new DataTable( "DataRowDebuggerTable" );
      using( Stream dataStream = objectProvider.GetData() )
      {
        BinaryFormatter formatter = new BinaryFormatter();
        table = formatter.Deserialize( dataStream ) as DataTable;
      }

      DataRowForm frm = new DataRowForm( table );
      windowService.ShowDialog( frm );
    }
  }

Pretty straight forward code, you're overriding the Show method to get the DataTable, creating a new Windows Form object (yup, you have to create it but it's not hard, really, it's not, just all a constructor taking a DataTable to populate a DataGridView object), then show that form.

 At this point, we need to test it out!  Cool!  If you read my Take Two blog, you'll know  you can copy the DLL to your Users directory.  The EASIEST way to do this is to let Visual Studio do it for you upon successful compile.  Huh?  What do I mean?  Build Events are a GREAT VS feature and I encourage you to check them out!  The code I think you'll want to use is this, it will copy the class library DLL into your correct Users directory.

xcopy "$(SolutionDir)$(ProjectName)\$(OutDir)$(TargetFileName)" "$(USERPROFILE)\Documents\Visual Studio 2010\Visualizers" /y

Now this does make SOME assumptions.  Please make sure you're solution and project names match up with what's in Visual Studio Solution Explorer.  How will you know if it's wrong?  You'll see error messages pointing to this line and you'll have to debug into the macro variables (those are the pieces with the $(MacroName).

Once you build it and everything works correctly you'll see a new file in your Users directory.

Deliverables location

Then when you run one of the test projects (if you're using my source code, COOL!) then you'll be able to see a magnifying glass on any DataRow variable when you hit the Debugger.Break() command.

DataRow with magnifier

When you click the magnifing glass, you'll see your new and improved debugger visualizer with all your contextual information in it's full glory!  LOL!

DataRow ebuggerVisualizer

Ok, at this point, you're probably MORE than ready to move onto implementing the DataRow[] debugger visualizer right?  Wouldn't it be GREAT to treat your DataRow[] just like a DataTable?  I mean when you're whipping up a .Select(); on a DataTable, it's nice to poke into the returning DataRow[] right?

DataRow[] default debugger

hhmmm I'm afraid I have some bad news for you.  DOH!  Hey, don't shoot the messanger, I spent four nights FIGHTING with this too ya know!  I'm not very happy neither!  But as it turns out, when the MSDN article talked about not being able to write these things for Arrays, they really did mean ANY Arrays, including the [ ] types.  Crap!

Here's what Spike and Peter Ritchie replied to my post on stackoverflow.

stackoverflow replies

 Both replies reiterate what I had already read, but most importantly, they confirmed what was finger flicking my brain and laughing at me for wasting all that time.  BUT as Shane would say, I now KNOW this stuff cold!  HAHA  I DID learn something here.  I can write custom debugger visualizers and I know how to work around unserializable objects, just as long as they're not in an array.  DOH!

Oh, something on the side I learned, IF you are doing debugger visualizers, you'll REALLY want to check out the VisualizerDevelopmentHost object.  It helps with debugging your debugger visualizers.  Using my old way, you basically had to hunt'n'peck your way to success.  With the VisualizerDevelopmentHost, you're able to put breakpoints into your visualizer code, VERY cool when you're into some complex objects and conditions.  That first argument is what you want to debug into, and if you've read THIS far, and STILL awake, I'm pretty sure you can figure out the rest. LOL

VisualizerDevelopmentHost host = new VisualizerDevelopmentHost( 
	row, 
	typeof( DataRowDebuggerVisualizer ), 
	typeof( DataRowVisualizerObjectSource ) );
host.ShowVisualizer();

I want to change Peter Ritchie and Spike for their confirmation over at stackoverflow.

Now that you know how to write a DataRow debugger visualizer, it's time to grab a coffee and get coding. 

 

Resources:

Source code: http://www.pchenry.com:8080/svn/blog/trunk/2010/DebuggerVisualizers

PCHenry.com: Visual Studio Debuger Visualizer (Take Two)

MSDN: How to: Write a Visualizer

MSDN: How to: Specify Build Events (C#)

stackoverflow: Trying to get a DataRow[] Debugger Visualizer to work in Visual Studio 2010

stackoverflow: Debugger Visualizer and "Type is not marked as serializable"

Tags:
Categories:
Location: Blogs Parent Separator TechTidBits

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Add Comment   Cancel 
     
  
Copyright 1999-2012 by PCHenry.com   Terms Of Use  Privacy Statement