Click here to Skip to main content
Click here to Skip to main content
Go to top

Need a SetConfig method for your Configuration Settings? What about an AppSettingsWriter?

, 20 Jan 2006
Rate this:
Please Sign up or sign in to vote.
Here are the configuration classes that allow you to modify your config file.

Introduction

I've been using the System.Configuration classes in all kinds of applications and services. I find them very useful, and until recently, it was all that I needed to work with the XML application settings.

Background

I've made a Visual Studio add-in. I intend to publish an article about that too. Actually, I got the idea on writing this article about configuration settings while I was working on the add-in. So, this add-in has a main form that you can click on in order to set some options and start the action. The first idea that came to my mind was to add the App.config file to store the predefined options and load them while starting. The next second, I realized that there’s no exe output from my solution so I cannot have an App.config file. Moreover, it would be nice if the options, when modified, could be persisted into the config file. Well, that’s the intrigue.

Explaining the code

There are two classes:

  • ConfigurationSettingsRW,
  • AppSettingsRW

and an interface:

  • IConfigurationRWSectionHandler

corresponding to the ones in the System.Configuration namespace.

'RW' stands for 'Read Write'.

IConfigurationRWSectionHandler interface

public interface IConfigurationRWSectionHandler
{
    object Create(XmlNode section);
    void Persist(object config, XmlNode section);
}

The Create method implementation should take care of loading the data from the XmlNode into an instance of the desired type (e.g. a collection of some kind) that would be returned.

The Persist method implementation should consider the first parameter of the same type as the instance returned by the Create method and should modify the XmlNode parameter accordingly.

ConfigurationSettingsRW class

You have the AppSettings property and the GetConfig method of course, but they're not static. The config file path has to be passed as a string to the constructor when creating an instance of this class => no more naming conventions for the config file. There are two public methods dealing with the appSettings config section: LoadAppSettings and SaveAppSettings, with no parameters and no return (void). You have nothing in the AppSettings property until you call LoadAppSettings. Setting or adding a value of a specified key in appSettings is made by using the indexer of AppSettings with the string parameter and calling SaveAppSettings afterwards.

Besides the GetConfig public method, you have the corresponding SetConfig public method. Both are calling a private method named GetSectionData for getting the section XmlNode and the section handler interface. I did nothing about section groups... because I never used them. Feel free to extend the code in order to suit your needs.

private void GetSectionData(string sectionName, 
      out XmlNode sectionNode, out IConfigurationRWSectionHandler handler)
{
    sectionNode = null;
    handler = null;
    try
    {
        XmlDocument configXml = new XmlDocument();
        configXml.Load(this.configFilePath);
        XmlNode node = 
          configXml.SelectSingleNode(string.Format("configuration" + 
          "/configSections/section[@name='{0}']", sectionName));
        if (node != null)
        {
            sectionNode = 
              configXml.SelectSingleNode(string.Format("configuration/{0}", 
                                                             sectionName));
            string typeName = node.Attributes["type"].Value;
            Type type = Type.GetType(typeName);
            handler = (IConfigurationRWSectionHandler)
                       Activator.CreateInstance(type);
        }
    }
    catch (Exception ex)
    {
        throw new ConfigurationException(string.Format("Error" + 
                  " while loading {0} section.", sectionName), ex);
    }
}

The SetConfig method saves the data by calling the specified (by 'configuration/configSections/section/@type' value) IConfigurationRWSectionHandler.Persist method. Of course, GetConfig gets the data by calling the corresponding IConfigurationRWSectionHandler.Create method.

AppSettingsRW class

The constructor has to get the config file path as a string parameter.

There is the AppSettings public property of type NameValueCollection.

There are the LoadFromFile and SaveToFile public methods that do exactly what their names suggest. Check this out:

/// <summary>
/// Loads the <appSettings> config section data 
/// from the configuration file into the 
/// <code>appSettings</code> member of type 
/// <code>NameValueCollection</code>.
/// </summary>
public void LoadFromFile()
{
    if (appSettings == null)
    {
        try
        {
            XmlDocument configXml = new XmlDocument();
            configXml.Load(this.configFilePath);
            XmlNode appSettingsNode = 
                configXml.SelectSingleNode("configuration/appSettings");
            if(appSettingsNode.LocalName=="appSettings")
            {
                NameValueSectionHandler handler = 
                    new NameValueSectionHandler();

// The NameValueCollection instance returned by the 'Create' method is readonly.
// Assigning this instance to 'appSettings' member would not allow modifications.
// It seems that by passing this instance to the NameValueCollection constructor
// there is a similar instance created that is NOT readonly. Hmmm...
                appSettings = new NameValueCollection(
                    (NameValueCollection)handler.Create
                    (null, null, appSettingsNode));

            }
        }
        catch (Exception ex)
        {
            throw new ConfigurationException("Error while loading appSettings." +
                " Message: " + ex.Message, ex);
        }
    }
}

/// <summary>
/// Loops through the <code>appSettings</code> NameValueCollection 
/// and recreates the XML nodes of the <appSettings> config 
/// section accordingly. It saves the configuration file afterwards.
/// </summary>
public void SaveToFile()
{
    if (appSettings != null)
    {
        try
        {
            XmlDocument configXml = new XmlDocument();
            configXml.Load(this.configFilePath);
            XmlNode appSettingsNode = 
                configXml.SelectSingleNode("configuration/appSettings");
            appSettingsNode.RemoveAll();
            for (int i = 0; i < appSettings.Count; i++)
            {
                string key = appSettings.GetKey(i);
                string val = appSettings.Get(i);

                XmlNode node = configXml.CreateNode
                    (XmlNodeType.Element, "add", "");

                XmlAttribute attr = configXml.CreateAttribute("key");
                attr.Value = key;
                node.Attributes.Append(attr);

                attr = configXml.CreateAttribute("value");
                attr.Value = val;
                node.Attributes.Append(attr);

                appSettingsNode.AppendChild(node);
            }
            configXml.Save(this.configFilePath);
        }
        catch (Exception ex)
        {
            throw new ConfigurationException
                ("Error while saving appSettings.", ex);
        }
    }
}

And there are two other public methods: GetValue and SetValue. I'm sure you guessed what these are for. Check the source file for details.

Using the code

You can include the source file (ConfigurationSettingsRW.cs) in your project and use the classes in the same manner as you'd use the System.Configuration classes, with the few differences and additions described above. Check out the available sample solution and sources (ConfigurationSettingsRW_src.zip) to see how it's done. The config file's schema must be the one you know from the .NET Framework, with the 'configSections', 'appSettings', and everything else.

As I mentioned, I intend to write an article about some add-in. That would be a good usage sample, and I guess I could insert a link to it as soon as I get it done. Until then, you have a demo project available for download.

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

Share

About the Author

Alexandru Stanciu
CEO http://startech.ro
Romania Romania
No Biography provided

Comments and Discussions

 
QuestionFileUpload control for mobile application PinmemberSheris18-Feb-09 3:20 
AnswerRe: FileUpload control for mobile application PinmemberAlexandru Stanciu18-Feb-09 3:42 
GeneralRe: FileUpload control for mobile application PinmemberSheris23-Feb-09 16:12 
GeneralDude, most of us come to see how to use your code Pinmemberdeerchao14-Aug-07 1:51 
GeneralRe: Dude, most of us come to see how to use your code PinmemberAlexandru Stanciu14-Aug-07 2:18 
GeneralRe: Dude, most of us come to see how to use your code Pinmemberdeerchao14-Aug-07 2:34 
GeneralAn alternative PinmemberDrew Noakes23-Jan-06 23:37 
GeneralRe: An alternative PinmemberEdwin Roetman24-Jan-06 22:24 
For an alternative, please take a look at my article "Easily store form- and application-settings using Isolated Storage":
http://www.codeproject.com/dotnet/IsolatedStorageMadeEasy.asp
 
This describes about the same functionality to store settings but does it in Isolated storage instead of config-file.
 
Edwin.

GeneralNormally not allowed PinmemberRamon Smits22-Dec-05 22:40 
AnswerRe: Normally not allowed PinmemberAlexandru Stanciu22-Dec-05 22:56 
GeneralRe: Normally not allowed PinmemberDanny Rodriguez23-Dec-05 3:13 
AnswerRe: Normally not allowed PinmemberAlexandru Stanciu23-Dec-05 5:16 
GeneralRe: Normally not allowed PinmemberGav_Roberts2k510-Jan-06 3:53 
GeneralRe: Normally not allowed PinmemberAlexandru Stanciu10-Jan-06 4:39 
GeneralRe: Normally not allowed PinmemberGav_Roberts2k510-Jan-06 4:50 
GeneralRe: Normally not allowed PinmemberJohn Whitmire11-Aug-06 9:54 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 20 Jan 2006
Article Copyright 2005 by Alexandru Stanciu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid