Message Maintenance Architecture with C# and XML






3.38/5 (6 votes)
Mar 4, 2005
4 min read

34485

2
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 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 "<" for "<" etc.
-->
<Messages>
<Message>
<MsgId>100</MsgId>
<MsgValue>Please Enter Project Name <MSG></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 "<MSG>". 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 <MSG>" 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
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.
<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
<%@ 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.