The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

Abacus (59) [Avatar] Offline
#1
I am using Visual Web Developer 2008 Express and generally add all program output to a string, which I then write to a text box on an aspx page.

Any tips on how I can use ObjectDumper? How can I access it, and how can I use it for output?

Thanks in advance.
fabrice.marguerie (224) [Avatar] Offline
#2
Re: ObjectDumper (p. 47)
You can adapt the code of the ObjectDumper class so that it writes to anything you want instead of Console.Out, which is the default.
Abacus (59) [Avatar] Offline
#3
Re: ObjectDumper (p. 47)
Hi Fabrice,

Thank you for your prompt reply.

If you have a moment, could you please tell me where to find the ObjectDumper class?

Thank you.

Abacus
fabrice.marguerie (224) [Avatar] Offline
#4
Re: ObjectDumper (p. 47)
You'll find it with the rest of the source code provided with the book. It's in the ObjectDumper.cs file.

PS: could you please provide more information in this thread?
jwooley (123) [Avatar] Offline
#5
Re: ObjectDumper (p. 47)
Take a look at the helper methods in the chapter 6-8 samples. In it, we intercept the call to the output stream and put it in the display label rather than sending it to the console.

The ObjectDumper is part of the LINQ samples available at http://msdn.microsoft.com/en-us/bb330936.aspx

Jim
Abacus (59) [Avatar] Offline
#6
Re: ObjectDumper (p. 47)
Hi Jim,

Thank you for the link and the other information. That's very helpful! I was wondering where the Microsoft samples were. (They are mentioned on p. 47 of LIA.)

Abacus
Abacus (59) [Avatar] Offline
#7
Re: ObjectDumper (p. 47)
Thank you, Fabrice.

What other information are you asking for?
fabrice.marguerie (224) [Avatar] Offline
#8
Re: ObjectDumper (p. 47)
It probably depends on the version of Visual Studio, but on my machine, Visual Studio's code samples are in "Csmilierogram FilesMicrosoft Visual Studio 9.0Samples". The CSharpSamples.zip file contains ObjectDumper.
Abacus (59) [Avatar] Offline
#9
Re: ObjectDumper (p. 47)
Hi Fabrice,

I did not download the whole of Visual Studio, just the Web Developer part. I have a folder Csmilierogram FilesMicrosoft Visual Studio 9.0, but there is no Samples folder in it.

I have the CSharpSamples.zip file somewhere, after downloading it for the Northwind database.
Abacus (59) [Avatar] Offline
#10
Re: ObjectDumper (p. 47)
Hi Fabrice,

I have found the ObjectDumper class file and will now try to figure out how to adapt it to VWD.

Cheers,

Abacus
jwooley (123) [Avatar] Offline
#11
Re: ObjectDumper (p. 47)
Object dumper essentially just calls Console.Write using reflection to access the various properties of the object. The real trick is intercepting the console stream and re-directing it so that you can output it to a label/textbox instead of the console. If you see the RunSample method of the MainForm in the Chapter 6-8 samples, you can see the implementation I adapted from the 101 LINQ samples implementation. The key here is using the Console.SetOut method to set the output to go to a memory stream instead of directly to the console window. Here's the code:

StreamWriter newOut = currentClass.OutputStreamWriter;
TextWriter output = Console.Out;
Console.SetOut(newOut);
MemoryStream baseStream = (MemoryStream)newOut.BaseStream;
baseStream.SetLength(0);
try
{
currentSample.Method.Invoke(currentClass, null);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.ToString());
}
newOut.Flush();
Console.SetOut(output); // I'm not sure if this is needed
OutputTextBos.Text = OutputTextBos.Text + newOut.Encoding.GetString(baseStream.ToArray());
fabrice.marguerie (224) [Avatar] Offline
#12
Re: ObjectDumper (p. 47)
I think that it would be easier to adapt the original code. It should not be difficult at all to make the class accept a TextWriter other than Console.Out. It could have a property "public TextWriter Log { get; set; }", just like DataContext has.
Abacus (59) [Avatar] Offline
#13
Re: ObjectDumper (p. 47)
Here is a simplified version of ObjectDumper that seems to work in VWD:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;

using System.Data.Linq.Mapping;
using System.Data.Linq;

using System.Reflection;

/// <summary>
/// Summary description for ObjectStringDumper
/// </summary>
///
namespace eukalemia.practice.csharp
{
public class ObjectStringDumper
{
private string s;
private int pos;
private int level;
private int depth;

public ObjectStringDumper()
{
s = String.Empty;
pos = 0;
level = 0;
depth = 0;
}

public string Write(object element)
{
Write(element, 0);
return s;
}

private void Write(object element, int depth)
{
this.depth = depth;
WriteObject(null, element);
}

private void Write(string t)
{
// Appends t to s

if (t != null)
{
s += t;
pos += t.Length;
}
}

private void WriteIndent()
{
// If level is n, indents by 2n spaces

for (int i = 0; i < level; i++)
{
Write(" "); // two spaces
}
}

private void WriteLine()
{
s += "
";
pos = 0;
}

private void WriteTab()
{
// Ensures that tab stops occur in multiples of eight spaces

Write(" "); // two spaces
while (pos % 8 != 0)
{
Write(" "); // one space
}
}

private void WriteValue(object o)
{
if (o == null)
{
Write("null");
}
else if (o is DateTime)
{
Write(((DateTime)o).ToShortDateString());
}
else if (o is ValueType || o is string)
{
Write(o.ToString());
}
else if (o is IEnumerable)
{
Write("...");
}
else
{
Write("{ }");
}
}


private void WriteObject(string prefix, object element)
{
if (element == null || element is ValueType || element is string)
{
WriteIndent();
Write(prefix);
WriteValue(element);
WriteLine();
}
else
{
IEnumerable enumerableElement = element as IEnumerable;
if (enumerableElement != null)
{
foreach (object item in enumerableElement)
{
if (item is IEnumerable && !(item is string))
{
WriteIndent();
Write(prefix);
Write("...");
WriteLine();
if (level < depth)
{
level++;
WriteObject(prefix, item);
level--;
}
}
else
{
WriteObject(prefix, item);
}
}
}
else
{
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
WriteIndent();
Write(prefix);
bool propWritten = false;
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
if (propWritten)
{
WriteTab();
}
else
{
propWritten = true;
}
Write(m.Name);
Write("=");
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string))
{
WriteValue(f != null ? f.GetValue(element) : p.GetValue(element, null));
}
else
{
if (typeof(IEnumerable).IsAssignableFrom(t))
{
Write("...");
}
else
{
Write("{ }");
}
}
}
}
if (propWritten) WriteLine();
if (level < depth)
{
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
Type t = f != null ? f.FieldType : p.PropertyType;
if (!(t.IsValueType || t == typeof(string)))
{
object value = f != null ? f.GetValue(element) : p.GetValue(element, null);
if (value != null)
{
level++;
WriteObject(m.Name + ": ", value);
level--;
}
}
}
}
}
}
}
}
}
}
jwooley (123) [Avatar] Offline
#14
Re: ObjectDumper (p. 47)
Nice work. One suggestion, replace your string with a string builder. You're putting a lot of pressure on the GC with all of the string concatenation. Thanks for posting the code.

Jim
Abacus (59) [Avatar] Offline
#15
Re: ObjectDumper (p. 47)
Thank you, Jim. Great idea.

Would Write(object element, int depth) ever be needed externally? If so, it could be made to return s, and Write(object element) could simply return Write(element, 0).
jwooley (123) [Avatar] Offline
#16
Re: ObjectDumper (p. 47)
You probably would want to expose the depth externally. By default the ObjectDumper only dumps one level. Exposing the depth externally allows the calling code to indicate how deep down the heirarchy you want to traverse. In the case of LINQ to SQL, setting the depth beyond 0 will mean lazy loading child collections during the iteration which is not something to take lightly.

Jim
Abacus (59) [Avatar] Offline
#17
Re: ObjectDumper (p. 47)
Hi again, Jim,

When I followed your suggestion to use a StringBuilder instead of a string, the page was processed in half the time (5 sec instead of 10). I also found that increasing the tab size from two to five spaces produced nicer formatting of the output. The improved version of my dumper class is now as follows (in case anyone else would like to use it):

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;

using System.Data.Linq.Mapping;
using System.Data.Linq;

using System.Reflection;
using System.Text; // need for StringBuilder

/// <summary>
/// Summary description for ObjectStringDumper
/// </summary>
///
namespace eukalemia.practice.csharp
{
public class ObjectStringDumper
{
private StringBuilder s;
private int pos;
private int level;
private int depth;

public ObjectStringDumper()
{
s = new StringBuilder(5000);
// empty string with initial capacity of 5000 characters

pos = 0;
level = 0;
depth = 0;
}

public string Write(object element)
{
return Write(element, 0);
}

public string Write(object element, int depth)
{
this.depth = depth;
WriteObject(null, element);
return s.ToString();
}

private void Write(string t)
{
// Appends t to s

if (t != null)
{
s.AppendFormat(t);
pos += t.Length;
}
}

private void WriteIndent()
{
// If level is n, indents by 2n spaces

for (int i = 0; i < level; i++)
{
Write(" "); // two spaces
}
}

private void WriteLine()
{
s.Append("
");
pos = 0;
}

private void WriteTab()
{
// Ensures that tab stops occur in multiples of eight spaces

Write(" "); // five spaces
while (pos % 8 != 0)
{
Write(" "); // one space
}
}

private void WriteValue(object o)
{
if (o == null)
{
Write("null");
}
else if (o is DateTime)
{
Write(((DateTime)o).ToShortDateString());
}
else if (o is ValueType || o is string)
{
Write(o.ToString());
}
else if (o is IEnumerable)
{
Write("...");
}
else
{
Write("{ }");
}
}


private void WriteObject(string prefix, object element)
{
if (element == null || element is ValueType || element is string)
{
WriteIndent();
Write(prefix);
WriteValue(element);
WriteLine();
}
else
{
IEnumerable enumerableElement = element as IEnumerable;
if (enumerableElement != null)
{
foreach (object item in enumerableElement)
{
if (item is IEnumerable && !(item is string))
{
WriteIndent();
Write(prefix);
Write("...");
WriteLine();
if (level < depth)
{
level++;
WriteObject(prefix, item);
level--;
}
}
else
{
WriteObject(prefix, item);
}
}
}
else
{
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
WriteIndent();
Write(prefix);
bool propWritten = false;
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
if (propWritten)
{
WriteTab();
}
else
{
propWritten = true;
}
Write(m.Name);
Write("=");
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string))
{
WriteValue(f != null ? f.GetValue(element) : p.GetValue(element, null));
}
else
{
if (typeof(IEnumerable).IsAssignableFrom(t))
{
Write("...");
}
else
{
Write("{ }");
}
}
}
}
if (propWritten) WriteLine();
if (level < depth)
{
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
Type t = f != null ? f.FieldType : p.PropertyType;
if (!(t.IsValueType || t == typeof(string)))
{
object value = f != null ? f.GetValue(element) : p.GetValue(element, null);
if (value != null)
{
level++;
WriteObject(m.Name + ": ", value);
level--;
}
}
}
}
}
}
}
}
}
}