Monday, January 10, 2011

Storing User Settings

I mentioned last week I want to store all settings for my application as user settings so I won't write to app.config and require administrative privileges.  I didn't like the constraints imposed by the .NET Settings implementation, such as configuring user settings at compile time and using attributes.  After implementing my own key value store implementation I'm realizing I may use the .NET settings provider for application settings, since I want it strongly typed, to have default values, and to have validation, and my property bag like implementation for storing settings application extenders write. For example Jane user writes a plugin and can persist settings in the user directory of my application.  This scenario doesn't work using LocalFileSettingsProvider.

Here is my initial key value store implementation:

using System.Configuration;
using System.Xml;
 
public sealed class DebuggerSettings
{
    public string this[string propertyName]
    {
        get
        {
            var store = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            UserSettingsGroup values = (UserSettingsGroup)store.SectionGroups["userSettings"];
            if (values == null)
            {
                return null;
            }
            ClientSettingsSection myValues = (ClientSettingsSection)values.Sections[typeof(DebuggerSettings).FullName];
            if (myValues == null)
            {
                return null;
            }
            SettingElement setting = myValues.Settings.Get(propertyName);
            if (setting == null)
            {
                return null;
            }
            string returnValue = setting.Value.ValueXml.InnerText;
            return returnValue;
        }
        set
        {
            var store = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            UserSettingsGroup addSectionGroup = (UserSettingsGroup)store.SectionGroups["userSettings"];
            if (addSectionGroup == null)
            {
                addSectionGroup = new UserSettingsGroup();
                store.SectionGroups.Add("userSettings",addSectionGroup);
            }
            string sectionName = (typeof(DebuggerSettings).FullName);
            ClientSettingsSection clientSettingsSection = (ClientSettingsSection)addSectionGroup.Sections[sectionName];
            if (clientSettingsSection == null)
            {
                clientSettingsSection = new ClientSettingsSection();
                clientSettingsSection.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
                addSectionGroup.Sections.Add(sectionName, clientSettingsSection);
            }
            SettingElement addMe = new SettingElement(propertyName, SettingsSerializeAs.String);
            XmlElement element = new XmlDocument().CreateElement("value");
            element.InnerText = value;
            addMe.Value.ValueXml = element;
            clientSettingsSection.Settings.Add(addMe);
                
            store.Save();
        }
    }
}

2 comments:

David Lemieux said...

You're aware that every access to every property of yours will cause disk reads and writes operations? Seems pretty unefficient to me. Why don't you instead load your configuration once, access or set the properties as you please and call a Save document whenever you want to commit to disk?

David Smith said...

Great point David.