Wednesday, December 09, 2015

StackTrace Does The Detective Work

I had a really weird bug that I just could not track down. I have 3 Windows Service applications that “talk” to each other, passing data back and forth and logging bits of that data in each of their databases. In this particular case, the 3 apps have all the same code, just different config files (in real life there would be more differences between them, additional DLLs, but for testing there isn’t). The bug wasn’t causing any exceptions to be thrown, there was just an empty string being stored in the database for one particular “transaction” and that bit of data should have had some content,  not an empty string.

This is a rather tough situation to debug in Visual Studio, due to the fact that I’ve only got one of the apps running from VS and the other two are running from their EXEs (all as Console apps for testing, rather than as Windows Services). The one I have running from VS is not the one causing the issue, so I can’t easily debug without re-arranging all the config files so that I can run the problem one in VS. So, instead of doing that, I write the data out to XML files here and there throughout the process and I can look at the XML files to help find the problem. Unfortunately, this wasn’t working this time because all the data looked fine!

Consequently, I had no idea where this was going wrong. I only knew that right before the data was saved to the database (from a common Save method that is called throughout the app), that the Agency column was empty. Since this method is called from many places, it was going to be difficult to find which calling code caused the problem without debugging. Then I hit on an idea … maybe I could use StackTrace while the code was running! I didn’t know if that was possible, but it turns out that it is and it helped solve my perplexing bug. Here’s what I did:

In the DataAccess class method that saves the data, I check if the Agency string is null or empty and if so, I then call the following TroubleShootEmptyAgency() method:

private void TroubleShootEmptyAgency(string Agency, string Xml)
{
StringBuilder sb = new StringBuilder();
if (Agency == null)
sb.AppendLine("Null Agency");
else
sb.AppendLine("Empty Agency");

sb.AppendFormat("*** DataSet Content ***\r\n{0}\r\n***\r\n", Xml);

// Now, the fun part! The StackTrace!
System.Diagnostics.StackTrace stacktrace = new System.Diagnostics.StackTrace(true);
if (stacktrace != null)
{
sb.AppendLine("StackTrace:");
foreach (var frame in stacktrace.GetFrames())
{
sb.AppendFormat("{0}\n", frame.ToString());
}
}
// Write it to a File
System.IO.File.WriteAllText("EmptyAgency.xml", sb.ToString());
}

The StackTrace enabled me to see exactly what the call stack was that led up to the data trying to be saved with an empty Agency string. Consequently, I knew exactly which class and method was causing the problem (and then I clearly saw why that Agency string was empty there).

We all know that StackTrace can be very useful, but perhaps not everyone knows that it can be obtained from a running application. I didn’t know it until I tried it. Keep this in your bag of tricks, it just might come in handy!

Happy coding!