Month: September 2014

Calculator Letters Puzzle – Solved!

Posted on Updated on

Or, Fun with Lambdas and Set Functions!

The challenge:

This three-part challenge comes from listener Lou Gottlieb.
If you punch 0-1-4-0 into a calculator, and turn it upside-down, you get the state OHIO.
What numbers can you punch in a calculator, and turn upside-down, to get a state capital,
a country and a country’s capital?

Upside-down Calculator
Upside-down calculator letters are the alphabet we can use to solve this puzzle

Puzzle Location:
http://www.npr.org/2014/09/14/348220755/the-puzzle-and-the-pea

The Solution Revealed!

Screen Shot of Solution
Screen shot shows the state capital, country and world capital, all of which can be spelled using ‘Calculator Letters’
The first thing we need is a list of countries, state capitals, and world capitals. Fortunately, I already have files containing the required data (you can get those files if you download the solution code below):
  • State Capitals
  • World Capitals
  • Countries

I’ve included those data files in my code download; if you run my code, note that their path will be different on your PC than mine.

Next, we’ll make a list of the available letters, which I have listed in the image below:

Revised Calculator Letters
Image shows how we start with the calculator numbers, rotate them 180 degrees, them map them to letters. IN the case of 4, it could be either h or n.

Once we have the data, it is basically a matter of determining whether one string set is entirely included within another string set. In other words, we will ask, for a number of solution candidates, whether it is a proper subset of the set of calculator letters.

To determine whether we have a subset, it is fun to use the Linq built-in set operators. In particular, we can use the method ‘Except‘. I also could have used the HashSet functionality, which actually has a method named ‘IsProperSubSet’, but HashSet is not as convenient as Linq and I just wanted to crank-out some code!

Using Linq, we can determine that one string is a proper subset of another if, when we use Except on them, the result is the empty set, i.e. a list with no members. Examples:

  • “atlanta”.Except(“beignlos”) will return a list containing (‘a’, ‘t’), i.e. not a subset.
  • “cheyenne”.Except(“beignlos”) will return a list containing (‘c’, ‘h’, ‘y’). Also not a subset.
  • “boise”.Except(“beignlos”) returns the empty set, i.e. it is the answer!

Note: “beignlos” is a string containing all the calculator letters. The true benefit of the ‘Except’ method is apparent below:

Here’s a Super-Cool Sample of the .NET Set-Operator ‘Except’

var leftoverLetters = "boise".Except("beignlos");
if (leftoverLetters.Count() == 0)
	Console.WriteLine("Ding ding ding - we have a winner!");

Conclusion: ‘boise’ is a subset of ‘beignlos’ –> you can spell ‘Boise’ using upside down calculator letters, and the Except  function tells us that.

Use Set-Operators at Work, Too!

At work, I have recently used the ‘Except’ operator to find orders that were lost. Something along these lines: ‘var missing = outboundOrders.Except(inBoundOrders);

My guess is you can use the Except operator to identify a lot of other things!.

Using Lambdas as ‘First Class’ Objects

First, a little bit of terminiology: “First class objects” are objects that you can use like any other entity. Such uses include passing them as parameters. When you pass a Lambda expression as a parameter, you are taking advantage of the fact that Lambdas are first class objects.

Why did I tell you that? Because my code benefited from it in this fun little app. In particular, I have these needs:

  • I need to perform the same work on 3 different files (state capitals, world capitals, countries)
  • Each file has a different layout
  • I would like to write a single method to do the same work for each file
  • To do so, I could write 3 different lambdas; each knowing how to extract the candidate from a line in a file
  • And then pass each lambda as an input parameter it to my method
  • Benefit: I write one method, which uses a lambda to extract the candidate, instead of 3 methods, each with their own
    techinque to extract the candidates

Here’s the Code

private void btnSolve_Click(object sender, RoutedEventArgs e) {
  //Make a definition list of the calculator letters.
  //This maps letters to the numbers they represent in a calculator. 
  //Each letter is in lower case to make matching easier
  //Note: a 'tuple' is a type of anonymous class
  List<Tuple<char, int>> calculatorLetterMap = 
  new List<Tuple<char, int>>() { Tuple.Create('b', 8), 
    Tuple.Create('e', 3), 
    Tuple.Create('i', 1), 
    Tuple.Create('g', 6), 
    Tuple.Create('n', 4), 
    Tuple.Create('l', 7), 
    Tuple.Create('o', 0), 
    Tuple.Create('s', 5) 
  };

  //The next 3 lines process state capitals:
  Func<string, string> extractStatCap = (aLine => { 
      //Look for hyphen, take the rest of the line, trimmed, in lowercase
      return aLine.Substring(aLine.IndexOf('-') + 2)
      .TrimEnd()
      .ToLower(); 
      });
  List<string> stateCapHits = GetFileMatchesAgainstLetterSet(STATE_CAPITALS_FILE, 
                              calculatorLetterMap, extractStatCap);
  DisplayHits(stateCapHits, "State Capitals", calculatorLetterMap, txtResults);

			
  //Now world capitals:
  //The function is a bit more complicated because some names have spaces, such as 'Abu Dhabi'
  Func<string, string> extractPlaceFunc = (aLine => { 
    //Look for a tilde and take everything prior to it, removeing non-letters
    return aLine.Substring(0, aLine.IndexOf('~'))
          .Where(c => char.IsLetter(c))
          .Aggregate("", (p,c) => p + c); 
    });
    List<string> worldCapHits = GetFileMatchesAgainstLetterSet(WORLD_CAPITALS_FILE, 
              calculatorLetterMap, extractPlaceFunc);
    DisplayHits(worldCapHits, "World Capitals", calculatorLetterMap, txtResults);

			
    //Finally, country names:
    Func<string, string> extractCountryFunc = (aLine => aLine);
    List<string> countryHits = GetFileMatchesAgainstLetterSet(COUNTRIES_FILE, 
          calculatorLetterMap, extractCountryFunc);
    DisplayHits(countryHits, "Countries", calculatorLetterMap, txtResults);
  }

  /// <summary>
  /// Loops through a file and returns a list of every entry which
  /// can be composed solely with 'calculator letters'
  /// </summary>
  /// <param name="fName">The file containing things that might match</param>
  /// <param name="calculatorLetterMap">List of letters derived from upside-down 
  /// calculator numbers</param>
  /// <param name="extractPlaceFunc">Function to extract the item of interest 
  /// from each line in the file</param>
  /// <returns></returns>
  private static List<string> GetFileMatchesAgainstLetterSet(string fName, 
          List<Tuple<char, int>> calculatorLetterMap, 
          Func<string, string> extractPlaceFunc) {
  List<string> result = new List<string>();
  using (StreamReader sr = File.OpenText(fName)) {
    while (sr.Peek() != -1) {
      //Execute the Lambda provided by our caller:
      string candidate = extractPlaceFunc(sr.ReadLine());
      var leftOverLetters = candidate
        .ToLower()
        .Except(calculatorLetterMap.Select(m => m.Item1));
        //If there are no leftover letters, we have a winner!
        if (leftOverLetters.Count() == 0) {
        string propperCase = char.ToUpper(candidate[0]) + candidate.Substring(1);
        result.Add(propperCase);
      }
    }
  }

  return result;
}

  /// <summary>
  /// Displays every hit in the list with its equivalent in 'calculator letters'
  /// </summary>
  /// <param name="hitList">List if items to dispaly</param>
  /// <param name="caption">Caption, such as 'State Capitals'</param>
  /// <param name="calculatorLetterMap">List of letter/number pairs for translating</param>
  /// <param name="txtResult">Textbox to hold the result</param>
  private static void DisplayHits(List<string> hitList, string caption, 
        List<Tuple<char, int>> calculatorLetterMap, TextBox txtResult) {
    txtResult.Text += caption + "\n";
    foreach (string aHit in hitList) {
      string number = MapLettersToCalculatorNumbers(aHit, calculatorLetterMap);
      txtResult.Text += string.Format("\t{0} = {1}\n", number, aHit);
    }
  }

  /// <summary>
  /// Translates the puzzle answer ('candidate') back into 'Calculator letters'
  /// </summary>
  /// <param name="candidate">Such as 'boise' or 'benin' or 'lisbon'</param>
  /// <param name="calculatorLetterMap">List of letter/number pairs</param>
  /// <returns>A string composed of numerals</returns>
  private static string MapLettersToCalculatorNumbers(string candidate, 
    List<Tuple<char, int>> calculatorLetterMap) {
    string result = (from c in candidate
                     join m in calculatorLetterMap on c equals m.Item1
                     select m.Item2
                     ).Aggregate("", (p, c) => p + c);
    return result;
  }

Download the code here: Puzzle Code

Efficiently Protect Your Company from SQL Injection

Posted on Updated on

Most places I work don’t want to be bothered protecting themselves from hackers, an attitude I find hard to believe given that, almost every day, another company looses mega-bucks after failing to protect themselves.

What you will learn: How to protect yourself against SQL Injection with a few lines of really cool code that runs six times faster than a naive implementation.

Hacker

Why Don’t Most Folks Protect Themselves?

Most programmers think that hacker attacks are rare, and defending is work, so they’ll hope they get lucky. Sometimes I think they’re just burying their heads in the sand. The problem is, they aren’t thinking about how devastating one lucky hacker attack can be. A hacker attack can easily put a company out of business; just think what would happen if all your credit card info was stolen, or your database backups were destroyed!

Firewall
Firewalls are imperfect, just like every other human invention! Last week, Company X was attacked and their firewall did not save them!

The other mistake they make is assuming they are protected by technology X; usually they put all their trust in their firewall or https. Sorry, hackers have defeated those technologies plenty of times. Furthermore, most attacks from from disgruntled former employees or business associates. They already know your passwords, so they use one weak app to get through the fire wall, then exploit their loop hole to attack other apps. Bottom line: the best security is to never assume any technology is foolproof, always use defense-in-depth.

I’ll guarantee that the latest company who got hacked had that attitude; i.e. the guys who screwed-up assumed that they didn’t need to use precautions because technology X was enough.I hope they like sleeping in their cars! I know you don’t like sleeping in your car, so spend some time to prevent a catastrophe.

My Defense Task: Prevent SQL Injection

SQL Injection is when an attacker submits SQL in a string that you use to run as a query. Generally you are vulnerable when you build an ad hoc query and run it against your database. For example, if you append the contents of a textbox to your query, the attacker can turn part of your intended query into a comment and run his query after a truncated version of your query runs. Note: any string from the outside world is a potential threat, even XML from your corporate partners. They could have disgruntled employees, or they could be hacked, or someone could spoof their transmission.

Normally, you can protect yourself by using parameterized queries. My problem: our ERP controls access to our database, and I can’t force it to use parameterized queries. Solution: scrub all input to sanitize SQL key words. For example, if the user input contains the words ‘drop table foo’, you can inject a space, or other character, into either ‘drop’ or ‘table’. In other words, substitute ‘dr op table’ whenever you find ‘drop table’. That way, legitimate  text is still readable, but your database won’t run the query.

Screen shot showing SQL scrubbing
The top text has potentially dangerous SQL commands in it; the bottom shows the results of scrubbing SQL key words. Notice how the dangerous phrase ‘delete from foo’ has been replaced with ‘d elete from foo’. A human can still read the text, but your database will not execute this command.

Scrub Efficiently with Regular Expressions!

Your naive coworker will conduct six different search-and-replace operations. I assert that this is six times too slow. Instead, be smart, use regular expressions: then you can only make one pass through your text!

Naive Approach:

public string SlowScrub(string cleanMe) {
  string result = cleanMe.Replace("Drop Table", "D rop Table")
                         .Replace("Select ", "S elect ")
                         .Replace("Update ", "U pdate ")
                         .Replace("Delete ", "D elete ")
                         .Replace("Insert ", "I nsert")
                         .Replace("Truncate Table ", "T runcate Table ");
  return result;
}

There are three problems with the code above:

  1. It makes 6 passes through your string, that slows-down your app
  2. It is case sensitive (and the Replace method won’t allow you to change that problem)
  3. It won’t catch Truncate Table or Drop Table when split across two lines

Regular Expressions to the Rescue

Here’s how I used a regular expression to make 1 pass through my string. The regular expression is a pattern to replace in the string. I also used a lambda (anonymous function) that .NET executes on every match it finds – how cool is that!

public string ScrubSql(string cleanMe) {
  string pattern = @"(          #Start our capture group
            (?:drop\stable)     #Non-capturing group 1; the word 'drop', space, then 'table'
            |                   #or
            (?:select\s)        #Non-capturing group 2: select' followed by whitespace
            |                   #Or
            (?:update\s)        #Non-capturing group 3; update' followed by whitespace
            |                   #or
            (?:delete\s)        #Non-capturing group 4; 'delete' followed by whitespace
            |                   #or
            (?:insert\s)        #Non-capturing group; the word 'insert' followed by whitespace
            |
            (?:truncate\stable) #'truncate table'
          )";

  string result = Regex.Replace(cleanMe, pattern, (m) => {
                    //This anonymous function is run on every match
                    string danger = m.Groups[1].Value.ToLower();
                    return danger.StartsWith("dr") ? "d rop t able "
                         : danger.StartsWith("s") ? "s elect "
                         : danger.StartsWith("u") ? "u pdate "
                         : danger.StartsWith("de") ? "d elete "
                         : "i nsert";
		 },
		RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace 
		| RegexOptions.Multiline | RegexOptions.Singleline);
  
  return result;
}

Notes:

  • I include comments in my regular expression; that helps make it easier to maintain. # is the comment char
  • This only works if I also specify ‘IgnorePatternWhitespace’ and ‘MultiLine’
  • My Search Pattern consists of six different choices, the same choices I showed you in my naive implementation.
  • The pipe character | means ‘or’ when used in a regular expression; it separates the for choices
  • Note that I supply a function (a ‘MatchEvaluator’) that .NET runs for every match it finds
  • My MatchEvaluator serves to identify which dangerous text it identified in the input string
  • And then it returns an appropriate sanitized string
  • Note that I also specified ‘IgnoreCase’
  • Also: the RegexOption ‘SingleLine’ is a bit confusing. It basically means “match your text as if it were a single line”, with the effect that, when your pattern seeks 2 words, it will find them even if on separate lines.

Bottom Line

You can easily plug-in my little function to your code. Every string you get from the outside world, use my funciton to scrub that string. The job you save may be your own!

Download the Code!

Download sample

Simple XPath Usage

Posted on Updated on

If you’re like me, you use a zillion different techniques, but some only rarely. I learned XPath a long time ago, and haven’t used it lately. So, I had to struggle a bit to make it work this time around. To make it easier next time, I’m saving my code where I can find it again quickly. You might find it useful too!

My Task: Extracting Custom Fields from XML

Our ERP allows us to create custom fields, as many as we want; it stores our custom fields in XML format. Here’s a sample, with the fields whimsically renamed to protect everyone’s privacy:

<?xml version="1.0"?>
<ArrayOfEntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Account Manager</Name>
		<Value>Marge Innovera</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Temporary Housing Provider</Name>
		<Value>Horseshoe Road Inn</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Weight Loss Consultant</Name>
		<Value>Hugh Jazz</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Collection Agent</Name>
		<Value>Amanda Recconwith</Value>
	</EntityPropertyOfString>
	<EntityPropertyOfString>
		<Name>Audiologist</Name>
		<Value>Isabelle Ringing</Value>
	</EntityPropertyOfString>
</ArrayOfEntityPropertyOfString>

My task: extract a couple of these fields and send the values to our eCommerce partner. For example, let’s say I need the name of our Audiologist, ‘Isabelle Ringing’, for our partner. The tool to use is XPath, which is designed for that very purpose. In fact, the XPath query to extract her looks like this:

/ArrayOfEntityPropertyOfString/EntityPropertyOfString[Name=’Audiologist’]/Value

What this XPath query does is:

  • Start at the root, represented by the forward slash ‘/’.
  • From there, find the child XML node named ‘ArrayOfEntityPropertyOfString
  • Find a grandchild node named ‘EntityPropertyOfString
  • With a Name having a value of ‘Audiologist
  • From that node, descend one more level to the child node ‘Value
  • Once we have that node, we can extract its inner text, which should be ‘Isabelle Ringing’

For a tutorial on XPath syntax, you could try W3Schools.

Tip: Use Notepad++ Plugins to Get Started

Notepad++ has a ton of useful plugins, you can use the XML tools for building and testing XPath queries. Start by asking it to give you a starter XPath query, as shown in the screen shot below:

Screen Shot Showing Notepad++ Plugin for XML
The current XML path is part of my XPath query; I just need to add the part where I select using the value of the Name child node

Once you have the XML path, you can modify it to meet your exact needs. If you don’t have the XML Tools Plugin, use the Plugin Manager to download it – the price is free.

Use your XPath Query in Code

I needed different fields from that same XML at different points, so I wrote a routine to extract different field values based on the name. That allowed me to reuse the code a couple times.

using System.Xml;
using System.IO;

public static string ExtractCustomField(string xml, string fieldCaption) {
  string result = "";
  if (!string.IsNullOrWhiteSpace(xml)) {
    string xPath = "/ArrayOfEntityPropertyOfString/EntityPropertyOfString[Name='{0}']/Value";
    string xPathQuery = string.Format(xPath, fieldCaption);
    XmlDocument xDoc = new XmlDocument();
    //We need a stream to load the XML, and StringReader works fine
    StringReader sr = new StringReader(xml);
    xDoc.Load(sr);
    XmlNode targetNode = xDoc.SelectSingleNode(xPathQuery);
    if (targetNode != null) {
      result = targetNode.InnerText;
    }
  }
  return result;
}

And, here is some sample usage:

string xml = ErpGetCustomFieldXml(orderId);
string audiologist = ExtractCustomField(xml, "Audiologist");
string collectionAgent = ExtractCustomField(xml, "Collection Agent");

One more Notepad++ tip: you can use it to test your XPath queries, which is a lot easier than doing so in your code!

Step One: Use the Menu to Start testing your XPath Query
Step One: Use the Menu to Start testing your XPath Query
Step Two: Enter your XPath Expression and See the Results
Step Two: Enter your XPath Expression and See the Results

Alternate Means to the Same End

I could have done a couple different techniques:

  1. Regular expression. Problem: each node would require a slightly different regex
  2. Linq to XML. [Edit: I wasn’t familiar with Linq to XML until now. Having spent a couple hours studying it, it seems somewhat easier than XPath.]
private string ExtractCustomField(string xml, string fieldCaption) {
  XDocument myXDoc = XDocument.Load(new StringReader(xml));
  //Try and get the Audiologist's name
  var matches = from n in myXDoc.Descendants("EntityPropertyOfString")
                where n.Element("Name").Value == "Audiologist"
                select n.Element("Value").Value;

  string result = (matches.Count() > 0)
                ? matches.FirstOrDefault()
                : "";
  return result;
}

 

Summary

XPath allows you to search for the field you want. If you write a reusable method, you can extract different field values by passing a field name and reuse the same code.

Make Debugging Easier with my Complex Object Visualizer

Posted on Updated on

Use Reflection to Display Complex Objects While Debugging!

Problem: it is hard to inspect complicated objects in the debugger. Lately, I’ve been testing a lot of web services and using complex objects form 3rd party libraries. These objects are big, complicated chunks of data. If you’re like me, you might feel frustrated inspecting them in the debugger. Nested properties can be a pain, especially in huge lists. What I find particularly irritating is, having scrolled deep, deep down into a big nested object, is accidentally clicking away and loosing the whole freakin’ thing! It would be better if I could dump the entire object somewhere like the output window or an unused TextBox. And that’s just what I’ve done!

Inspecting Complex Objects In the Debugger
When dealing with big classes, it can be challenging to find the value you need top see, especially if you don’t know the field or property name.

Reflection to the Rescue

if you’re familiar with the .NET Reflection API, you know that you can use it to examine or manipulate any programming object. I decided to use Reflection to display my complex objects by converting them to a nice, easy-to-read string.

Visualizing Complex Objects
Screen shot shows an arbitrary class being displayed as a string. The same code will display other complicated object structures during debugging sessions.

Benefits

If you download my code, compile it into a dll, you can add it to any project. Next time you’re debugging, just use my method to blast your objects into a textbox or the output pane!  You get instant visibility into complex, nested objects.

Nuts and Bolts: Reflection Methods that Make it Happen

I used these methods to generate a string representation of arbitrary objects:

  • GetValue – retrieves the property value for your class instance, using a PropertyInfo object representing the property in question
  • GetFields – I could have used it, but didn’t, because Web Services don’t return objects with fields. But! You can modify my code to do so, if desired.
    • GetProperties – retrieves all properties for any class type. In the example above, it retrieved, for example, ‘ShipToAddress’, ‘Name’, ‘Street1’, Orders (an array) etc.

‘GetProperties’ returns an array of PropertyInfo objects; each PropertyInfo has

  • PropertyType – for example, if the PropertyInfo represents my OrderID, then the PropertyType will be int
  • Name – for example, ‘OrderId’

I also used the following property of the ‘Type’ class:

  • IsArray – for an arbitrary type, tells you whether it is an array. I think it works for Lists as well, but I didn’t test, because, again, web services return arrays by default, and I’m testing Web Services right now.

Take a Look at the Short, Sweet Code!

// Returns a nice string representation of an arbitrary object, useful for debugging
public static string ComplexObjectToString(object someClassInstance, int indentLevel = 0) {
    StringBuilder sbResult = new StringBuilder();
    Type classType = someClassInstance.GetType();
    PropertyInfo[] allProperties = classType.GetProperties(BindingFlags.Public 
                                    | BindingFlags.DeclaredOnly | BindingFlags.Instance);

    //If the current property is an array, loop through each entry and 
    //display the member values, indented 4 characters deeper:
    if (someClassInstance is IEnumerable && !(someClassInstance is string)) {
        foreach (var anItem in (IEnumerable)someClassInstance) {
            if (IsNotCoreType(anItem.GetType()))
                sbResult.AppendFormat("{0}", anItem);
            else {
                string theItem = ComplexObjectToString(anItem, indentLevel + 4);
                sbResult.Append(theItem);
            }
            sbResult.AppendLine("---------------------");
        }
    } else {
        string indentSpaces = new string(' ', indentLevel);
        foreach (PropertyInfo pi in allProperties) {
            //Handle arrays and lists:
            if (IsEnumerable(pi.PropertyType)) {
                object subProperty = pi.GetValue(someClassInstance, null);
                sbResult.AppendLine(pi.Name + " items:");
                foreach (var anItem in (IEnumerable)subProperty) {
                    string subProps = ComplexObjectToString(anItem, indentLevel + 4);
                    sbResult.Append(subProps);
                    sbResult.AppendLine(new string(' ', indentLevel) + "------");
                }
            } else if (IsNotCoreType(pi.PropertyType)) {
                //Handle nested complex objects:
                object subProperty = pi.GetValue(someClassInstance, null);
                if (subProperty != null) {
                    sbResult.AppendFormat("{0}{1}:\n", indentSpaces, pi.Name);
                    string subProps = ComplexObjectToString(subProperty, indentLevel + 4);
                    sbResult.Append(subProps);
                }
            } else {
                if (!_UnwantedProperties.Contains(pi.Name)) {
                    //Handle normal properties, using the Name from the PropertyInfo and 
                    //GetValue to retrieve each successive value
                    object propVal = pi.GetValue(someClassInstance, null);
                    sbResult.AppendFormat("{0}{1}:\t{2}\n", indentSpaces, pi.Name, propVal);
                }
            }
        }
    }
    return sbResult.ToString();
}

public static bool IsEnumerable(Type theType) {
    return theType.IsArray || 
                    ( 
                    theType != typeof(string)
                    &&
                    theType.GetInterfaces().Any(t => t == typeof(IEnumerable))
                    );
}

/// <summary>
/// Determines whether a given object is a 'built-in' class, such as int, 
/// DateTime, string, etc.
/// </summary>
/// <param name="type">A type which might be a 'built-in' class</param>
/// <returns>True when the class needs to have its properties displayed</returns>
public static bool IsNotCoreType(Type type) {
    return !type.IsPrimitive && !type.ToString().StartsWith("System.");
    //return (type != typeof(object) && Type.GetTypeCode(type) == TypeCode.Object);
}

/// <summary>
/// These properties apply to every class, and I don't want to see them:
/// </summary>
private static string[] _UnwantedProperties = new string[] { "ExtensionData", "IsReadOnly", 
                            "IsFixedSize", "IsSynchronized", "Length", 
                            "LongLength", "Rank", "SyncRoot" };

}

Put it to Work and Visualize Your Data!

So, download my sample project. Extract the class ‘Utility’ and modify (it if you want). For example, you might want to see private properties or fields in your output (not there in this version); that would be easy for you to plug in. Now, build a class library; compile it to a dll. Add your dll to your project! Next debug session, use my class on your huge object back and spit-it-out into a textbox or the immediate pane of the debugger. Frustration relieved!

Screen shot shows how to print text to the output pane
You can print your complex object to the output console from the immediate pane, that can be handy when stopped on a breakpoint. In this case, the code that I executed was a Console.WriteLine using the string output from Utility.ComplexObjectToString()

 Future Directions

  1.  If you’re feeling ambitious, you could adapt my technique to create your own fantastically useful Visual Studio Plug-in! http://msdn.microsoft.com/en-us/vstudio/vextend.aspx
  2. You could also consider using the Visual Studio T4 code generator in conjunction with the technique demonstrated here. For example, you could use it to generate label/textbox pairs, on-the-fly, for any class T4 Code generation:. http://msdn.microsoft.com/en-us/library/bb126445.aspx
  3. You could also incorporate it into your logging routines; that would allow you to capture the complete state of an object that might be misbehaving.

Update

I tweaked it some; I enhanced it to handle lists. I also added a universal XML serializer to the project, as part of the download.

Download

Code Link Download:  Visualize Complex Objects. Note: recently revised to expose the functionality as a separate project, built as a dll.