Dot Net Perls

Use XML Logging With LINQ - C#

by Sam Allen

Problem

You want to add XML-based logging to your .NET application. You can use XElement and LINQ-to-XML to update your XML file of log messages. Your solution must be simple to code and easy to maintain.

Solution: C#

Our tools are LINQ, C# 3.0, and Visual Studio 2008 with .NET 3.5. We combine design patterns with functional programming in LINQ for reliable results. The examples here really drive home the power of LINQ.

Example: main XML logging class

The example here is a singleton and contains some code to make adding logging messages easier. Put this code a new file, such as "XmlLog.cs". In ASP.NET, use the App_Code folder, which allows better protection and organization.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.Linq;

public sealed class XmlLog
{
    static string _fileName;
    XElement _x;

    static readonly XmlLog _instance = new XmlLog();
    public static XmlLog Instance
    {
        get
        {
            return _instance;
        }
    }

    private XmlLog()
    {
        //
        // Load the log.
        //
        _fileName = HttpContext.Current.Request.MapPath("~/App_Data/Log1.xml");
        _x = XElement.Load(_fileName); // Root element.
    }

    /// <summary>
    /// Add the message to our XML log.
    /// </summary>
    /// <param name="message">Message you want to add.</param>
    public void Add(string message)
    {
        //
        // New element with message and filename.
        //
        XElement newLine = new XElement("Entry", message + this.CurrentFile);
        _x.Add(newLine);
        _x.Save(_fileName);
    }

    public void Clear()
    {
        _x.RemoveNodes();
        _x.Save(_fileName);
    }

    public string CurrentFile
    {
        get
        {
            return " (" + HttpContext.Current.Request.FilePath + ")";
        }
    }
}

Question: how can I use this code?

By accessing the static property. Use a catch block to write to the XML error log. This is very simple and will result in one disk operation, a Save().

try
{
    //
    // Do calculations.
    // May raise an exception if something goes wrong!
    //
}
catch
{
    //
    // Write to the XML error log.
    //
    XmlLog.Instance.Add("Constructor error");
    return;
}

Question: what does the XML output look like?

It is very simple. XML documents must have a container element, and then nested elements. The XML log here has only two types of elements: the container and then entry elements.

<?xml version="1.0" encoding="utf-8"?>
<MainLog>
    <Entry>Constructor error (File.aspx)</Entry>
</MainLog>

Question: how can I display the XML in a page?

With a foreach loop. XElement and LINQ provide good ways for us to read in XML and display it. Here is the .aspx markup and code you will need. You can name this page Log.aspx.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server" type="text/C#">
    protected void Page_Load(object sender, EventArgs e)
    {
        string clearLog = Request.QueryString["clear"];
        if (clearLog == "true")
        {
            XmlLog.Instance.Clear();
            Response.Redirect(ResolveUrl("~/Log.aspx"));
            return;
        }

        string addLog = Request.QueryString["add"];
        if (addLog != null)
        {
            XmlLog.Instance.Add(addLog);
        }

        //
        // Display the log.
        //
        string pathLoc = System.Web.HttpContext.Current.
            Server.MapPath("~/App_Data/Log1.xml");

        //
        // Open the XElement.
        //
        System.Xml.Linq.XElement doc = System.Xml.Linq.XElement.Load(pathLoc);

        //
        // Use StringBuilder to build up the results HTML.
        //
        StringBuilder builder = new StringBuilder();
        foreach (System.Xml.Linq.XElement x in doc.Elements())
        {
            builder.Append("Log entry: ").Append(x.Value).Append("<br/>\n");
        }
        LogDiv1.InnerHtml = builder.ToString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"><title>Log</title></head>
<body>

<div id="LogDiv1" runat="server" />

<a href="Log.aspx?clear=true">Clear log</a><br />
<a href="Log.aspx?add=test">Add message</a><br />

</body>
</html>

Question: anything else?

Look at how in Log.aspx we use a Response.Redirect when clear=true is received. This means the log user won't accidentally clear it by reloading. This code, including all the file IO works well in medium trust. XML can implement IO functionality on your shared host.

Summary: using XML logging

XML logging has advantages and allows you to save files easily. The singleton helps improve performance and clarity, and LINQ and XElement also work towards those goals.

Dot Net Perls
About
Sitemap
Source code
RSS
File I/O
Excel Interop Use
Using StreamReader
Recursive File and Directory List
ReadLine for Reading File Into List
File Handling
Recent
Pi
NGEN Installer Class
List Element Equality
DateTime Tips and Tricks
Remove HTML Tags From String
© 2008 Sam Allen. All rights reserved.