
Introduction
The architects at Microsoft have adopted various strategies over the years for managing configuration settings. First there was the .INI file, then the system registry, and most recently something called the configuration file. There's no doubt that the methods used to store and retrieve configuration settings have changed dramatically over time. The funny thing, to me anyway, is that during that same stretch of years my needs as a developer haven't really changed much at all. What I wanted back in 1988 isn't much different than what I want today, which is an easy way to store and retrieve my configuration settings.
Towards that end, this article presents a component that reads and writes configuration settings to a xml file. That file can either be maintained alongside the executable, or in user specific isolated storage. The contents of the file can also be encrypted, just in case you happen to be storing sensitive information.
One quick note: the code I'm presenting here isn't intended to replace the classes in the System.Configuration namespace. I offer my code as an alternative for those instances where your storage needs are simple, and you have a desire to manage things visually within Visual Studio .NET.
Using the component at design-time
There are two classes of interest: Setting, and SettingContainer. As their names imply, SettingContainer holds a collection of Setting objects. The SettingContainer class reads and writes the value of each Setting object to and from disk. The Setting class is used to hold the value for each configuration setting.
Here is a look at the design-time properties for the SettingContainer class:

The EncryptedStorage property is used to encrypt the value of each setting value in the settings file. Enable this feature if you are concerned about storing sensitive information on the hard-drive.
The FileName property is used to determine the name of the file to use at runtime.
The IsolatedStorage property is used to determine where the settings file should be maintained. If your configuration settings will vary from one user to another then you should probably enable this property.
The Settings property contains the collection of Setting objects. Here is what it looks like when you click the Settings property at design-time:

Each Setting instance contains design-time properties for DefaultValue, and StorageKey.
The DefaultValue property is the value that will be given back to your application whenever a valid runtime value can't be obtained, such as when the underlying settings file hasn't been written to disk.
The StorageKey property is the name that will be used to store the values associated with that Setting in the settings file.
Using the component in your code
As far as using the code goes, you should start by reading the settings file like this:
private void MainForm_Load(object sender, System.EventArgs e)<BR>{<BR> m_settingContainer.Read();<BR>}
After a read operation, the SettingContainer fills all the associated Setting objects with their stored values, and fires the SettingRead event. A good way to update your application with the new setting values is to intercept the SettingRead event like this:
private void m_settingContainer_SettingRead(object sender, System.EventArgs e)<BR>{<BR> m_textBoxSetting1.Text = m_setting1.CurrentValue;<BR> m_textBoxSetting2.Text = m_setting2.CurrentValue;<BR>}
CurrentValue will contain one of two things: the value that was last stored to disk, or the default value that was entered at design time.
Storing configuration settings to disk is accomplished through the Write method of the SettingContainer class. Here is an example of that:
private void m_buttonWrite_Click(object sender, System.EventArgs e)<BR>{<BR> m_settingContainer.Write();<BR>}
Just before the SettingContainer writes the Setting values to disk, it fires the SettingWrite event. This gives an application the opportunity to update the current value of each Setting object. Here is an example of how to intercept and use that event:
private void m_settingContainer_SettingWrite(object sender, System.EventArgs e)<BR>{<BR> m_setting1.CurrentValue = m_textBoxSetting1.Text;<BR> m_setting2.CurrentValue = m_textBoxSetting2.Text;<BR>}
That's really all there is to using my component in your application. The approach may not be as flexible as the classes in System.Configuration, but they are arguably easier to use and have the added advantage of integrating with the Visual Studio.NET design-time environment. So, as far as modifying xml files and source files whenever you need to add or remove a setting - well, as my wife (who is from Brooklyn, NY) is so fond of saying, "fahget about it"!
Interesting parts
The reading/writing code is pretty simple. I use the XmlTextWriter class to write the values to disk, and I use the XPathDocument and XPathNavigator classes to read those values back out again. I'm sure the reading could have been done better, but my needs when I wrote the code were immediate and simple. So, feel free to improve things if you like.
The encryption code is right out of the Microsoft sample, so I wont go over that either. It's not the strongest encryption approach ever (I stored the key in the code), but again, it serves my immediate needs.
To me, the most interesting thing about the SettingContainer class is the design-time support for the Settings property. I started by implementing the property as follows:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]<BR>[Editor(typeof(PrivateSettings.Design.SettingCollectionEditor),<BR>typeof(UITypeEditor))]<BR>public SettingCollection Settings<BR>{<BR> get {return m_coll;}<BR>}<BR>
The Settings property returns an instance of the SettingCollection class, which is an internal class that derives from CollectionBase, and is used to hold the actual collection of Setting objects. The actual implementation of SettingCollection is trivial, so I wont list it here.
The Settings property is adorned with the DesignerSerializationVisibility attribute, which tells Visual Studio.NET to generate the code to reproduce the collection at runtime. The other attribute tells Visual Studio.NET that this property should use the SettingCollectionEditor class at design-time. The SettingCollectionEditor class itself is a specialized collection editor that creates a default StorageKey value whenever a new Setting object is added to the collection. The code for SettingCollectionEditor is shown here:
internal class SettingCollectionEditor : CollectionEditor<BR>{<BR> public SettingCollectionEditor(System.Type type)<BR> : base(type)<BR> {<BR> }<BR> protected override System.Object CreateInstance(System.Type itemType)<BR> {<BR> if (itemType == typeof(Setting))<BR> {<BR> Setting x = (Setting)base.CreateInstance(itemType);<BR> x.StorageKey = x.Site.Name + "Key";<BR><BR> return x;<BR> }<BR><BR> return base.CreateInstance(itemType);<BR> }<BR>}
The only other interesting things include my discovery of the ToolboxItem attribute, which may be used to prevent a component from automatically showing up in the toolbox. In this case, since a user should never create a Setting object outside of SettingContainer, it didn't seem right that the component should show up in the toolbox. The other interesting feature of the Setting class is my use of the DesignTimeVisible attribute, which prevents Setting instances from showing up in the component tray at design-time. In this case, I want to force users to interact with Setting objects throught the Settings property of the SettingContainer class. Here is what the two attributes look like on the Setting class.
[DesignTimeVisible(false), ToolboxItem(false)]<BR>public class Setting : System.ComponentModel.Component<BR>{<BR>}
Conclusion
That's it! I hope that this component will be of some use to you. It has quickly become one of my favorites, simply because it makes it so easy to add or remove individual settings from my configuration files as I'm writing my code.
Have fun! :o)