I was writing some code Friday, and I realized I was working with three
of my favorite namespaces all at once: System.IO, System.Xml, and System.Diagnositcs.
Most people will have used all of these namespaces at least once, but there are a
bunch of hidden gems that not everyone will have seen.
The task I was trying to pull off was to dump an XML document for debugging
purposes. I wanted to send it both to the console and to a logfile, to give me a real-time
idea of what was going on as well as a permanent record I could go back and analyze
later.
The ability to write a piece of information to more than one place
for diagnostic purposes just cries out for System.Diagnostics.Trace.
So I started my program off with the following lines of code:
using System;
using System.IO;
using System.Diagnostics;
public class App
{
public static void Main()
{
Trace.Listeners.Add(
new TextWriteTraceListener(Console.Output));
string logfile =
DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss")
+ ".txt";
Trace.Listeners.Add(
new TextWriteTraceListener(logfile);
which sets it up so that any time I call Trace.WriteLine,
a piece of text is written both to the command console and to a logfile whose name
is derived from the current date and time. The overload of ToString that
lets you specify the exact format for the date and time is pretty cool, I think.
Later, when I wanted to actually dump the XML, I did this:
StringWriter sw = new StringWriter();
XmlTextWriter wtr = new XmlTextWriter(sw);
wtr.Formatting = Formatting.Indented;
xml.WriteTo(wtr);
Trace.WriteLine(sw.ToString());
wtr.Close();
where xml is the XmlDocument that
I wanted to dump out.
There are a number of cool things in these few lines of code:
· The StringWriter class
give you a stream that you can use anywhere you’d use a normal TextWriter (e.g.
the constructor of XmlTextWriter),
but it writes to an internally maintained StringBuilder instead.
Handy.
· The Formatting property
of XmlTextWriter to get that nice “every
nested element gets indented one level” look. Makes for much more readable output.
· Of
course, the call to Trace.WriteLine to
actually spew this same XML to more than once place.
A few caveats:
· You
need to define the symbol TRACE in your build (Project Properties->Configuration
Properties->Build->Conditional Compilation Constants – just type in TRACE)
or Trace.WriteLine will not even make
it into the compiled program.
· I
found that I needed to go through and flush each trace listener independently, or
my log file would get truncated. That was easy, though: just a foreach loop over the Trace.Listeners collection,
calling Flush and Close on
each TraceListenener.