Thursday, 30 June 2011

Leveraging LINQPad’s Object Visualisation in Visual Studio

When you run a query in LINQPad it produces formatted output on the results tab that you can optionally export to Word, Excel or HTML. Here I show two techniques for visualising any arbitrary .NET object.

The first way is non-invasive, i.e., requires no change to your Visual Studio solution or compiled assemblies.

The second way is invasive but allows you to export any arbitrary .NET object to HTML by leveraging LINQPad’s Dump() extension method.

Technique 1: Add a Visual Studio LINQPad Debugger Visualizer

Download the LINQPad Visualizer from Google Code and follow the instructions from the point where it says “If using the download do this:.”

You should also remember to unblock the DLLs after downloading. Consider this simplified code with fields made public for brevity.

class User
{
public int UserId;
public List<Course> Courses;
public List<Student> Students;
}

class Course
{
public string CourseCode;
}

class Student
{
public int StudentId;
}


Set up a collection of Users.



var users = new List<User> {
new User {
UserId = 1,
Courses = new List<Course> {
new Course {
CourseCode = "ECU120"
},
new Course {
CourseCode = "ECU121"
},
new Course {
CourseCode = "ECU122"
},
},
Students = new List<Student> {
new Student {
StudentId = 1
},
new Student {
StudentId = 2
},
}
},
new User {
UserId = 2,
Courses = new List<Course> {
new Course {
CourseCode = "ECU124"
},
new Course {
CourseCode = "ECU125"
},
new Course {
CourseCode = "ECU126"
},
},
Students = new List<Student> {
new Student {
StudentId = 1
},
new Student {
StudentId = 3
},
}
},
new User {
UserId = 3,
Courses = new List<Course> {
new Course {
CourseCode = "BESU022"
},
new Course {
CourseCode = "BESU023"
},
new Course {
CourseCode = "ECT034"
},
},
Students = new List<Student> {
new Student {
StudentId = 1
},
new Student {
StudentId = 2
},
}
},
};

users.Dump();



Then we can debug into it.



image



To do this set a watch for your object of interest. Here we are inspecting the users collection. In order to view its contents we need to enter



new System.WeakReference(users)



in the Name column as shown.



Clicking on the dropdown for Value shows two LINQPad debugger visualizers. The default visualizer is a JSON visualizer that allows us to see the contained values of objects that haven’t been marked as Serializable. Clicking on the visualizer pops up a Windows Form containing the object’s values.



image



In this case we lose the type information but we can still see all the values neatly laid out.



However, if we mark the User, Student and Course classes as Serializable



[Serializable]
class User
{
public int UserId;
public List<Course> Courses;
public List<Student> Students;
}

[Serializable]
class Course
{
public string CourseCode;
}

[Serializable]
class Student
{
public int StudentId;
}



Then select the lower LINQPad visualizer we get the type information as well and with neater layout.



image



Technique 2: Add a Reference to LINQPad.exe



For this technique we add a reference to LINQPad.exe that allows us to leverage LINQPad’s Dump() extension method for any object…



/// <summary>
///
LINQPad extension methods.
/// </summary>
public static class LinqPadExtensions
{
/// <summary>
///
Writes object properties to HTML
/// and displays them in default browser.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="o"></param>
/// <param name="heading"></param>
public static void Dump<T>(
this T o,
string heading = null
)
{
string localUrl =
Path.GetTempFileName() + ".html";
using (
var writer =
LINQPad.Util.CreateXhtmlWriter(true)
)
{
if (!String.IsNullOrWhiteSpace(heading))
writer.Write(heading);
writer.Write(o);
File.WriteAllText(localUrl, writer.ToString());
}
Process.Start(localUrl);
}
}



Then we can write users.Dump() as in the example above. On execution this writes the object’s values to HTML and launches the default web browser. This produces the same results as the typed version above.



image



This method has been adapted from an example on StackOverflow. One issue to be aware of is that your project should target the full .NET 4, not the Client Profile.