How to load a separate Application Settings file dynamically and merge with current settings?

22,786

Well, this works:

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;

public static class SettingsIO
{
    internal static void Import(string settingsFilePath)
    {
        if (!File.Exists(settingsFilePath))
        {
            throw new FileNotFoundException();
        }

        var appSettings = Properties.Settings.Default;
        try
        {
            var config = 
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.PerUserRoamingAndLocal);

            string appSettingsXmlName = 
Properties.Settings.Default.Context["GroupName"].ToString(); 
// returns "MyApplication.Properties.Settings";

            // Open settings file as XML
            var import = XDocument.Load(settingsFilePath);
            // Get the whole XML inside the settings node
            var settings = import.XPathSelectElements("//" + appSettingsXmlName);

            config.GetSectionGroup("userSettings")
                .Sections[appSettingsXmlName]
                .SectionInformation
                .SetRawXml(settings.Single().ToString());
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("userSettings");

            appSettings.Reload();
        }
        catch (Exception) // Should make this more specific
        {
            // Could not import settings.
            appSettings.Reload(); // from last set saved, not defaults
        }
    }

    internal static void Export(string settingsFilePath)
    {
        Properties.Settings.Default.Save();
        var config = 
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.PerUserRoamingAndLocal);
        config.SaveAs(settingsFilePath);
    }
}

The export method creates a file like the following:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <userSettings>
        <MyApplication.Properties.Settings>
            <setting name="SineWaveFrequency" serializeAs="String">
                <value>1</value>
            </setting>
            <setting name="SineWaveAmplitude" serializeAs="String">
                <value>100</value>
            </setting>
            <setting name="AdcShift" serializeAs="String">
                <value>8</value>
            </setting>
            <setting name="ControlBitsCheckedIndices" serializeAs="String">
                <value>0,1,2,3,5,6,7,8</value>
            </setting>
            <setting name="UpgradeSettings" serializeAs="String">
                <value>False</value>
            </setting>
        </MyApplication.Properties.Settings>
    </userSettings>
</configuration>

The import method parses that file, takes the everything inside the node, puts that XML into the user.config file at the appropriate section, then reloads the Properties.Settings.Default in order to grab those values from the new user.config file.

Share:
22,786
Pat
Author by

Pat

Previously a "Software Engineer" at a small electronics design shop, now a mostly JS and python dev interested in learning, doing, and teaching.

Updated on July 09, 2022

Comments

  • Pat
    Pat almost 2 years

    There are questions pertaining to reading settings from a separate config file and others similar to it, but my question is specific to application property settings (i.e. <MyApplication.Properties.Settings> - see XML file below) and how to load them dynamically. I tried the method in this post, which involved refreshing the entire appSettings section of the main config file, but my adaptation threw exceptions because I wasn't replacing the appSettings section:

    var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
    // Have tried the other ConfigurationUserLevels to no avail
    config.AppSettings.File = myRuntimeConfigFilePath;
    config.Save(ConfigurationSaveMode.Modified); // throws ConfigurationErrorsException
    ConfigurationManager.RefreshSection("userSettings");
    

    The ConfigurationErrorsException.Message is "The root element must match the name of the section referencing the file, 'appSettings' (C:\myFile.xml line 2)." The file is:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <userSettings>
            <MyApplication.Properties.Settings>
                <setting name="SineWaveFrequency" serializeAs="String">
                    <value>6</value>
                </setting>
                <setting name="SineWaveAmplitude" serializeAs="String">
                    <value>6</value>
                </setting>
            </MyApplication.Properties.Settings>
        </userSettings>
    </configuration>
    

    Is there a way to import the values from this file into the MyApplication.Properties.Settings.Default class, with the framework handling all XML deserialization like it does when the config file is loaded on application startup?

  • Pat
    Pat about 14 years
    Note, you must add a reference to the System.Configuration assembly.
  • Eric Bellet
    Eric Bellet almost 5 years
    what it is Properties? I copied and pasted the code and I received this error "The name "Properties" does not exist in the actual context"