Since asp.net 1.0/1.1, I enjoyed storing my settings in web.config because it’s both fast and convenient.
<appSettings>
<add key="activeEnvironment" value="dev"/>
</appSettings>
Reading them is straightforward enough:
ConfigurationManager.AppSettings["activeEnvironment"].ToString();
Since .net 2.0/3.5 I wanted to do more than read settings, I wanted to be able to modify them on the fly.
I thought this method would be convenient:
ConfigurationManager.AppSettings.Set("activeEnvironment", "prod");
The documentation was also simple:
// Summary:
// Sets the value of an entry in the System.Collections.Specialized.NameValueCollection.
//
// Parameters:
// name:
// The System.String key of the entry to add the new value to. The key can be
// null.
//
// value:
// The System.Object that represents the new value to add to the specified entry.
// The value can be null.
//
// Exceptions:
// System.NotSupportedException:
// The collection is read-only.
I developed an administration page that handles system settings modification by
calling ConfigurationManager.AppSettings.Set(key, value)
Since calling this static method, I was able to notice the website behave appropriately
according to the settings that I had set.
I did however notice that the setting value at web.config did not change
as I initially assumed. Were was the method storing it?
Here were also some interesting feedback in using this method. The answer is cache.
Why did the .net framework team design it this way? Pretty useless method don’t you think?
Anyway, ranting obviously isn’t going to solve my problem. Such case cannot work in an enterprise level web application,
so I designed my own and simple Settings.xml file. I wanted it lightweight.
<?xml version="1.0" encoding="utf-8"?>
<Settings>
<setting>
<id>activeEnvironment</id>
<value>dev</value>
</setting>
</Settings>
The next piece of the puzzle was to design a helper class that would read and write the value, another opportune time for me to practice Linq to Xml.
Since I am lazy and wanted to take advantage of intellisense support, I created an enumeration object for the settings key.
public enum WebConfigSettings
{
activeEnvironment
}
What follows is the helper class definition:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Resources;
using System.Xml;
using System.Xml.Linq;
/// <summary>
/// Reads and updates XML settings migrated from web.config
/// </summary>
public static class xmlSettings
{
private static string settingsXmlFile =
HttpContext.Current.Server.MapPath("~/Settings.xml");
public static string readSetting(WebConfigSettings s)
{
string setting = "";
IEnumerable<string> xmlQuery =
from AllSettings in XElement.Load(settingsXmlFile).Elements("setting")
where (string)AllSettings.Element("id") == s.ToString()
select (string)AllSettings.Element("value");
foreach (string xmlSetting in xmlQuery)
setting = xmlSetting;
return setting;
}
public static void saveSetting(WebConfigSettings s, string proposedValue)
{
string xPath = "/Settings/setting[id='" + s.ToString() + "']/value";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(settingsXmlFile);
XmlNode node = xmlDocument.SelectSingleNode(xPath);
//remove existing value
node.ParentNode.RemoveChild(node);
//save in correct node
string xPathSettingsNode = "/Settings/setting[id='" + s.ToString() + "']";
XmlNode settingsNode = xmlDocument.SelectSingleNode(xPathSettingsNode);
//create new value
XmlElement ElementSetting = xmlDocument.CreateElement("value");
ElementSetting.InnerText = proposedValue;
settingsNode.AppendChild(ElementSetting);
//save Xml file
xmlDocument.Save(settingsXmlFile);
}
}
XPath is a query language best learned by example. XPath is a rich language in its own right, with a bezy of functions.
My usage for xPath was:
string xPath = "/Settings/setting[id='" + s.ToString() + "']/value";
This means I wanted to traverse the node “setting” and then get the “value” element given the “id” element as a parameter.
<setting>
<id>activeEnvironment</id>
<value>dev</value>
</setting>
Calling the read static method:
string activeEnvironment = xmlSettings.readSetting(WebConfigSettings.activeEnvironment);
Thanks to the enum, I do not have to remember the setting’s identifier.
Calling the save static method:
xmlSettings.saveSetting(WebConfigSettings.activeEnvironment,TextBox1_settings.Text);
This time, my custom settings are now stored in disk.
