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

2

13

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?

Zackzackariah answered 5/3, 2010 at 19:15 Comment(1)
In case you are curious about the motivation, see my prior question: How to use .NET configuration files (app.config, settings.settings) to save and restore all application data?. At that time, I didn't know the difference between app.config and user.config, but I am definitely looking for a solution to modify user.config.Zackzackariah
Z
9

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.

Zackzackariah answered 8/3, 2010 at 15:50 Comment(2)
Note, you must add a reference to the System.Configuration assembly.Zackzackariah
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"Puma
P
0

The solution suggested by Pat:

// Get the whole XML inside the settings node
var settings = import.XPathSelectElements("//" + appSettingsXmlName);

returns null. I changed it to

var settings = import.Element("configuration").Element("userSettings").Element(appSettingsXmlName);

config.GetSectionGroup("userSettings")
      .Sections[appSettingsXmlName]
      .SectionInformation
      .SetRawXml(settings.ToString());

And it works perfectly.

Potvaliant answered 19/11, 2011 at 14:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.