Click here to Skip to main content
16,021,209 members
Articles / Web Development / HTML
Article

Message Maintenance Architecture with C# and XML

Rate me:
Please Sign up or sign in to vote.
3.38/5 (6 votes)
4 Mar 20054 min read 34.4K   21   4
De-coupling Error Messages out of your web application.

Overview

In today’s IT world "Error Messages" or "Information Messages" in any systems are inevitable. In application development the messages are normally coupled into the system. So, whenever the customer asks for changes in messages, developers get into the code and change the messages, which is generally error prone. When trying to change the messages there are possibilities that new bugs may get introduced.

With the power of .NET and XML, it is possible to de-couple the messages outside the system and it is easy for maintenance. Whenever customer asks for change in messages, they themselves can go and change the messages in the XML repository or it is easy for any one who knows to operate the computers to change the messages without shutting down the application.

Let us have a look how we can achieve it with .NET and XML.

Brief Architecture Description

All the messages of the system are stored in the form of XML with unique ids. We can have a common method/function to retrieve the messages by passing their respective ids. In this way we can de-couple the messages outside the system. With powerful caching features available in .NET, we can cache the XML file and set a dependency to it. So, for the first request the XML file is cached in to the server’s memory and the subsequent requests will read from the cached object and service the client requests. We can even use resource files, but changing the resource files again needs to compile. Also, changing the XML doesn’t need restart of the server or application since it has cache dependency. So, whenever customer needs a change in messages he can just change the text in XML and the subsequent requests by the client to that particular message will be served with new messages.

Detailed Functional Description

1. XML Part

Let us have a look at the format of the XML.

XML
<?xml version="1.0" encoding="utf-8" ?>
<!--
1. Message Id should be maintained Unique. It will 
be a 3 Digit numeric and sequential.
2. Try to avoid "/", "\" and "<",">". Instead use "&lt;" for "<" etc.
--> 
<Messages>
 <Message>
  <MsgId>100</MsgId>
  <MsgValue>Please Enter Project Name &lt;MSG&gt;</MsgValue>
 </Message>
 <Message>
  <MsgId>101</MsgId>
  <MsgValue>Please Enter Project Date</MsgValue>
 </Message>
</Messages>
The XML file has root tag of "Messages". It has "Message" node, which has "MsgId" and "MsgValue" as its child nodes. Basically, these nodes have information about the Messages. Message Id (MsgId) is maintained as 3 digits, so that the first digit represents Module Id and the other 2 digits represents the Message. Number of digits can be changed depending upon the number of messages, Also it may have any combination of characters to be uniquely identified. For example, "MOD-001".

The "MsgValue" node contains the actual message to be displayed. The message should not have some XML reserved characters like "<" or ">" etc. If these characters or to be included in the message try give the HTML Encode value for it or add XML escape characters.

For example, Message like "Password can’t be blank" can be given as "Password can\’t be blank".

Have a look at the Message Value of Id 100 in the XML. The message has "&lt;MSG&gt;". This is a pattern given in the message which can be replaced and used for general messages. For Example. If you have messages that change only a part of sentence can be put as same and while calling the method/function, we can pass the value as parameter.

Consider these messages, "Please enter Project Name" and "Please enter Project Description". We can have single message in the XML like "Please enter Project &lt;MSG&gt;" and we can call it as GetMessage("100","Name") to display first message and GetMessage("100","Description") for second message. On seeing the code we will understand how it is possible.

2. C# Part

C#
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.Caching;
using System.Collections.Specialized;
using System.Xml;
using System.Xml.XPath;
using System.IO;

namespace CacheExample
{
    /// <SUMMARY>
    /// Summary description for ErrorMessage.
    /// </SUMMARY>
    public class ErrorMessage
    {
        public ErrorMessage()
        {
            //
            // TODO: Add constructor logic here
            //
        }
// Function Name            : (+) getErrorMsg
// Date                     : 5th March, 2005.
// By                       : Saravanan R Achari
// Purpose                  : To Retrieve the Error Message 
//                            from the Corresponding Modules (generalised).
// Input Parameters         : Expects a string denoting 
//                            the Error Message Required.
// Output Parameters        : Gives the Desired Error Message.
// Environmental Constraints: Expects the XML file having error messages.

    static public string GetMessage(string intErrId,string strOptErrMsg)
    {
      // String Dictionary to hold Cached Error Messages
          StringDictionary objStrDictionary    = new StringDictionary();    
      // object to Load XML document
      XmlDocument objXmlDocument        = new XmlDocument();        
      // to get XML Node list in the specifed Xpath
          XmlNodeList objNodeList;            
      string strXPath        = string.Empty;
      string strChildXPath    = string.Empty;
       string strFilePath    = string.Empty;    
      string strErrDescription= string.Empty;
       HttpContext objContext    = HttpContext.Current;
            
     try
     {
       strFilePath = objContext.Server.MapPath("ErrorMsg.xml");
            if (objContext.Cache["strdictErrorMsg"]== null)
        {
        strXPath = "Messages/Message";
        objXmlDocument.Load(strFilePath);
        objNodeList = objXmlDocument.SelectNodes(strXPath);
        foreach(XmlNode objNode in objNodeList)
        {
            objStrDictionary.Add(objNode.SelectSingleNode(
             "MsgId").InnerText,objNode.SelectSingleNode("MsgValue").InnerText);
        }
        CacheDependency dependency = new CacheDependency(
         objContext.Server.MapPath("ErrorMsg.xml")); 
        objContext.Cache.Insert("strdictErrorMsg", objStrDictionary,dependency);
         } // if ends here
         else
          {    
        objStrDictionary = (StringDictionary)objContext.Cache["strdictErrorMsg"];
          } // else ends here
        
          if(objStrDictionary.ContainsKey(intErrId))
        {
          strErrDescription = objStrDictionary[intErrId];
          if (strOptErrMsg != string.Empty)
           {
             strErrDescription = strErrDescription.Replace("<MSG>",strOptErrMsg);
           }
          return strErrDescription;
        }
        else
        {    
         strErrDescription="";
         return strErrDescription;
        }
                
    } // try block ends here
    catch (Exception ex)
    {
      return "Invalid Error Id / Module Name";
    } // Catch block ends here
            
     }
  }
}

In the C# code above, the high lighted code is important as it puts the StringDictionary object in to server’s cache, so that XML parsing needs not to be done for each request.

"StringDictionary" object is used as it is more efficient than "HashTable" as our collection contains only strings. The "ErrorMsg.XML" is the XML file mentioned above. Keep it in the application path so as for the above source code to work; else path should be changed in the code. "GetMessage" method accepts 2 parameters. The first Parameter is the MessageId and Second Parameter is the optional message to be shown with the required message. This scenario is discussed above. For general call the second parameter will be "string.Empty".

VB.NET users can convert the above code to VB.NET.

3. ASPX Part

Even JavaScript Messages in ASPX pages can be moved to this XML file. You can access the messages as shown in script below.

ASP.NET
<script language="javascript">
function test()
{
 var xyz = '<%=ErrorMessage.GetMessage ("101","")%>';
 alert(xyz);
}
</script>
Ensure the relevant namespaces are imported in the ASPX file.

For Example. Here my Namespace is

ASP.NET
<%@ Import Namespace="CacheExample"%>

Conclusion

You can enhance the above code for reusability. Certain customizations can be made like passing more than one custom message to the function and appropriately servicing the client etc. Hope this article helps you. Kindly send your clarifications and queries.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSame Method, but with App.config? Pin
Fresh Mexican Food Fan20-Mar-07 7:22
Fresh Mexican Food Fan20-Mar-07 7:22 
QuestionWhy? Pin
Richard Schneider9-Mar-05 19:33
Richard Schneider9-Mar-05 19:33 
I hate to be a kill joy but why go this way. Net provides the ResourceManager, resx files and satelite assemblies for translated error messages.

Also, I think message numeric message ids are wrong. Using a hierarchical name, such as Myorg.InvalidDocumentNumber is (a) more readable and (b) allows multiple system to be integrated.

Cheers,
Richard Schneider
AnswerRe: Why? Pin
sarav.r9-Mar-05 21:01
sarav.r9-Mar-05 21:01 
GeneralRe: Why? Pin
zulu10-Mar-05 2:18
zulu10-Mar-05 2:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.