Our error handler emails the SysAdmin exceptions. Right now they look bad as plain text.
Is there a way to take an Exception and format it into nice looking html so the SysAdmin can read it more easily?
<pre>
... htmlencoded output from Exception.ToString() goes here ...
</pre>
                        I would serialize the exception into an XML element and then I would format it with a custom XSLT.
There is an interesting approach about how to serialize an Exception which you can read about here: Serializing Exceptions to XML. To summarize it, if you try to decorate a custom class inheriting from System.Exception with the [Serializable] attribute and then use the XmlSerializer class on it, you will get a runtime exception because of the Exception.Data property, which is implementing System.Collections.IDictionary. So, you may easily use the new System.Xml.Linq API (new as of .NET 3.5).
Here is a simple program which generates an exception and formats it as HTML.
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using ConsoleApplication2.Properties;
class Program
{
    public static void Main(string[] args)
    {
        try
        {
            //throw an DivideByZeroException
            var a=0;
            var b=1/a;
        }
        catch (Exception ex)
        {
            //using the ExceptionXElement class
            var xmlException = new ExceptionXElement(ex);
            XslCompiledTransform myXslTrans = new XslCompiledTransform();
            //Resources.formatter is the xsl file added as a Resource to the project (ConsoleApplication2.Properties.Resources.formatter)
            //So, here we load the xsl
            myXslTrans.Load(XmlReader.Create(new StringReader(Resources.formatter)));
            //initialize a TextWriter, in this case a StringWriter and set it to write to a StringBuilder
            StringBuilder stringBuilder = new StringBuilder();
            XmlTextWriter myWriter = new XmlTextWriter(new StringWriter(stringBuilder));
            //apply the XSL transformations to the xmlException and output them to the XmlWriter
            myXslTrans.Transform(xmlException.CreateReader(), null, myWriter);
            //outputting to the console the HTML exception (you can send it as the message body of an email)
            Console.WriteLine(stringBuilder);
        }
    }
}
Here is the Formatter.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" encoding="utf-8" indent="no"/>
  <xsl:template match="/">
    <html>
      <body>
        <h1>
          <xsl:value-of select="name(/*)"/>
        </h1>
        <h2>
          <xsl:value-of select="//Message"/>
        </h2>
        <table border="1">
          <tr bgcolor="#9acd32">
            <th>StackTrace</th>
          </tr>
          <xsl:for-each select="//Frame">
            <tr>
              <td>
                <xsl:value-of select="."/>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
And here is the ExceptionXElement class definition:
using System;
using System.Collections;
using System.Linq;
using System.Xml.Linq;
/// <summary>Represent an Exception as XML data.</summary>
public class ExceptionXElement : XElement
{
    /// <summary>Create an instance of ExceptionXElement.</summary>
    /// <param name="exception">The Exception to serialize.</param>
    public ExceptionXElement(Exception exception)
        : this(exception, false)
    { }
    /// <summary>Create an instance of ExceptionXElement.</summary>
    /// <param name="exception">The Exception to serialize.</param>
    /// <param name="omitStackTrace">
    /// Whether or not to serialize the Exception.StackTrace member
    /// if it's not null.
    /// </param>
    public ExceptionXElement(Exception exception, bool omitStackTrace)
        : base(new Func<XElement>(() =>
        {
            // Validate arguments
            if (exception == null)
            {
                throw new ArgumentNullException("exception");
            }
            // The root element is the Exception's type
            XElement root = new XElement
                (exception.GetType().ToString());
            if (exception.Message != null)
            {
                root.Add(new XElement("Message", exception.Message));
            }
            // StackTrace can be null, e.g.:
            // new ExceptionAsXml(new Exception())
            if (!omitStackTrace && exception.StackTrace != null)
            {
                root.Add
                (
                    new XElement("StackTrace",
                        from frame in exception.StackTrace.Split('\n')
                        let prettierFrame = frame.Substring(6).Trim()
                        select new XElement("Frame", prettierFrame))
                );
            }
            // Data is never null; it's empty if there is no data
            if (exception.Data.Count > 0)
            {
                root.Add
                (
                    new XElement("Data",
                        from entry in
                            exception.Data.Cast<DictionaryEntry>()
                        let key = entry.Key.ToString()
                        let value = (entry.Value == null) ?
                            "null" : entry.Value.ToString()
                        select new XElement(key, value))
                );
            }
            // Add the InnerException if it exists
            if (exception.InnerException != null)
            {
                root.Add
                (
                    new ExceptionXElement
                        (exception.InnerException, omitStackTrace)
                );
            }
            return root;
        })())
    { }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With