|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionHere is another recipe for cooking up and serving your own configuration files. And I mean any configuration file, not just your ready-to-serve app.config and web.config files. Readers who need a refresher on the configuration file layout or mechanics can see prior articles published here or other references. BackgroundI’ve never enjoyed being served an appetizer with the entrée and desert at the same time or in the same dish - it just doesn’t taste right. Besides, one of the main imperial rules of programming says: first divide, then conquer. So our goal here will be to break up the monolithic app.config and web.config files and gain some freedom from their confines and rules, without loosing any of the conveniences they provide. In other words, separate the data that we would normally place in one configuration file into several config files, so we can use them where needed and as needed. In doing so, the applications we develop may stand a better chance of getting past the security guards at the production environment gates. We often hear people say, "Don’t place all your eggs in the same basket" - same idea here. The CodeHungry? Let’s turn to the recipe. In order to remain compatible with the methods of getting to the key-value pairs provided in our default configuration files, and because of the convenience they provide, we choose to simply inherit them from the using System;
using System.Xml;
using System.Reflection;
using System.Configuration;
using System.Windows.Forms;
public class AnyConfig : System.Configuration.AppSettingsReader
{
private XmlNode node;
private string _cfgFile;
public string cfgFile
{
get { return _cfgFile; }
set { _cfgFile=value; }
}
public string GetValue (string key)
{
return Convert.ToString(GetValue(key, typeof(string)));
}
public new object GetValue (string key, System.Type sType)
{
XmlDocument doc = new XmlDocument();
object ro = String.Empty;
loadDoc(doc);
string sNode = key.Substring(0, key.LastIndexOf("//"));
// retrieve the selected node
try
{
node = doc.SelectSingleNode(sNode);
if( node != null )
{
// Xpath selects element that contains the key
XmlElement targetElem= (XmlElement)node.SelectSingleNode(
key.Replace(sNode,"")) ;
if (targetElem!=null)
{
ro = targetElem.GetAttribute("value");
}
}
if (sType == typeof(string))
return Convert.ToString(ro);
else
if (sType == typeof(bool))
{
if (ro.Equals("True") || ro.Equals("False"))
return Convert.ToBoolean(ro);
else
return false;
}
else
if (sType == typeof(int))
return Convert.ToInt32(ro);
else
if (sType == typeof(double))
return Convert.ToDouble(ro);
else
if (sType == typeof(DateTime))
return Convert.ToDateTime(ro);
else
return Convert.ToString(ro);
}
catch
{
return String.Empty;
}
}
public bool SetValue (string key, string val)
{
XmlDocument doc = new XmlDocument();
loadDoc(doc);
try
{
// retrieve the target node
string sNode = key.Substring(0, key.LastIndexOf("//"));
node = doc.SelectSingleNode(sNode);
if( node == null )
return false;
// Set element that contains the key
XmlElement targetElem= (XmlElement) node.SelectSingleNode(
key.Replace(sNode,""));
if (targetElem!=null)
{
// set new value
targetElem.SetAttribute("value", val);
}
// create new element with key/value pair and add it
else
{
// handle xxx[@key='yyy']
sNode = key.Substring(key.LastIndexOf("//")+2);
// create new element xxx
XmlElement entry = doc.CreateElement(sNode.Substring(0,
sNode.IndexOf("[@")).Trim());
sNode = sNode.Substring(sNode.IndexOf("'")+1);
// set attribute key=yyy
entry.SetAttribute("key", sNode.Substring(0,
sNode.IndexOf("'")) );
// set attribute value=val
entry.SetAttribute("value", val);
node.AppendChild(entry);
}
saveDoc(doc, this._cfgFile);
return true;
}
catch
{
return false;
}
}
public bool removeElement (string key)
{
XmlDocument doc = new XmlDocument();
loadDoc(doc);
try
{
string sNode = key.Substring(0, key.LastIndexOf("//"));
// retrieve the appSettings node
node = doc.SelectSingleNode("//appSettings");
if( node == null )
return false;
// XPath select setting element that contains the key to remove
node.RemoveChild( node.SelectSingleNode(key.Replace(sNode,"")) );
saveDoc(doc, this._cfgFile);
return true;
}
catch
{
return false;
}
}
private void saveDoc (XmlDocument doc, string docPath)
{
// save document
// choose to ignore if web.config since it may
// cause server sessions interruptions
if( this._cfgFile.Equals("web.config") )
return;
else
try
{
XmlTextWriter writer = new XmlTextWriter( docPath , null );
writer.Formatting = Formatting.Indented;
doc.WriteTo( writer );
writer.Flush();
writer.Close();
return;
}
catch
{}
}
private void loadDoc ( XmlDocument doc )
{
// check for type of config file being requested
if( this._cfgFile.Equals("app.config"))
{
// use default app.config
this._cfgFile = ((Assembly.GetEntryAssembly()).GetName()).Name+
".exe.config";
}
else
if( this._cfgFile.Equals("web.config"))
{
// use server web.config
this._cfgFile = System.Web.HttpContext.Current.Server.MapPath(
"web.config");
}
// load the document
doc.Load( this._cfgFile );
}
}
Below is a public class FormConfig : System.Windows.Forms.Form { private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.DataGrid dataGrid1; private System.Windows.Forms.Button button1; private AnyConfig config; private DataSet ds; . . . static void Main() { Application.Run(new FormConfig()); } private void FormConfig_Load(object sender, System.EventArgs e) { config = new AnyConfig(); // set the document path\name config.cfgFile = "app.config"; // retrieve and output document values textBox1.Text = "Sample output from "+ config.cfgFile+":\r\n"; textBox1.Text+= config.GetValue("//appSettings//add[@key='one']"); // retrieve and output another document values config.cfgFile = "..\\..\\my.config"; textBox1.Text += "\r\n\r\nNow output from "+ config.cfgFile+" and DataGrid:\r\n"; DateTime date = (DateTime)( config.GetValue( "//allSettings//mySettings//set[@key='date']", typeof( DateTime )) ); date = date.AddMonths( 1 ); textBox1.Text+= date.ToShortDateString()+"\r\n"; textBox1.Text+= config.GetValue( "//allSettings//mySettings//set[@key='greeting']")+ " "+( config.GetValue( "//allSettings//mySettings//set[@key='salutation']") )+"\r\n"; textBox1.Text+= (bool)( config.GetValue( "//allSettings//mySettings//set[@key='switch']", typeof( bool )) ) +"\r\n"; // remove a key/value pair config.removeElement("//allSettings//mySettings//set[@key='makes']"); // add it back config.SetValue("//allSettings//mySettings//set[@key='makes']", "more sense" ); // retrieve and output values from another set of keys textBox1.Text+= config.GetValue( "//allSettings//yourSettings//your[@key='greeting']")+ " "+( config.GetValue( "//allSettings//yourSettings//your[@key='salutation']") )+"\r\n"; // display document ds = new DataSet(); ds.ReadXml(config.cfgFile); // dataGrid1.SetDataBinding(ds, "appSettings"); dataGrid1.DataSource = ds.Tables["allSettings"]; dataGrid1.Expand(-1); } } The output from the resulting application is the Windows form, shown here with
These are the app.config and my.config files we used as input: <?xml version="1.0" encoding="utf-8"?> <!-- app.config -->
<configuration>
<appSettings>
<add key="one" value="hello" />
<add key="testing" value="1234506" />
<add key="howdy" value="there" />
</appSettings>
</configuration>
<?xml version="1.0" encoding="utf-8"?> <!-- my.config -->
<configuration>
<allSettings>
<mySettings>
<set key="greeting" value="Hello" />
<set key="date" value="4/9/1945" />
<set key="test" value="makes sense" />
<set key="salutation" value="Mr." />
<set key="switch" value="True" />
<set key="makes" value="sense" />
</mySettings>
<yourSettings>
<your key="switch" value="False" />
<your key="greeting" value="Ciao" />
<your key="date" value="11/20/2003" />
<your key="test" value="987654" />
<your key="salutation" value="Ms." />
</yourSettings>
</allSettings>
</configuration>
Points of InterestThe One Snoopy likes surfing and snooping, the other sniffing and cooking. Enjoy cooking!
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||