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.
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.
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 + ")";
}
}
}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;
}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>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>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.
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.