+1  A: 

I do not think overriding the entire config file is a good idea. Some of the settings in this file might contain settings to be processed really early, before any of your code had a chance to do anything i.e. the ones related to the startup of .NET CLR.

mfeingold
It seems that you are right about not manipulating the entire file: In memory, at least, there are many more sections than just the "appSettings" one that I think I am interested in.To see what I mean, try var currentConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal); currentConfig.Dump();in LINQPad.
Pat
I've discovered that it isn't the "appSettings" value that I wanted to change, but the "userSettings" value. Specifically, it's the child node <MyApplication.Properties.Settings>.
Pat
+1  A: 

Since you app.config file is a simple xml file you can load it into an XDocument:

string path = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
XDocument doc = XDocument.Load(path);
//Do your modifications to section x
doc.Save(path);
ConfigurationManager.RefreshSection("x");


I corrected the XDocument.Load() code according to @Pat's comment

Manu
Thanks for the recommendation, but the path you specified is not the correct one for changing user settings. Also, in case anyone else wants to try this, Load is a static method of the XDocument class, so the syntax is var doc = XDocument.Load(path);. I'll continue to pursue reading and replacing sections of the XML file to see if this method works, but no luck yet.
Pat
The path should point to your App.config where I thought the section you want to manipulate is.
Manu
+2  A: 

It is best practice to NOT write to the app.config but use the settings file for saving user settings that are modified. The app.config and web.config should only be used for read only values.

Kenoyer130
OK, but how is that done? I am already using the settings file to persist user input between runs of the application, but how can I save and restore that information as a separate file (import/export)?
Pat
As the below post from Manu, just think of it as an XML file.
Kenoyer130
Again, how is that done? My understanding is that the settings "file" is really just app.config, seeing as that is where the settings are stored. Clarifications?
Pat
Now that I understand this all a bit better, I know that it isn't app.config that I wanted to modify. I am using Application Settings through the Settings Designer and binding them to properties in controls on my GUI. These properties are per-user, so they are stored in user.config (which is generated when the program executes - it's not in the VS solution).
Pat
A: 

Thanks to Manu's suggestion to just read the file as XML, I hacked together this solution. (It only works for in the current form for properties saved as strings, such as the Text property of a TextBox. It won't work, for instance, if you persist the Value property of a NumericUpDown control.) It works by using Export with a path to the file to save, which produces a file like the following:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <userSettings>
        <HawkConfigGUI.Properties.Settings>
            <setting name="FpgaFilePath" serializeAs="String">
                <value>testfpga</value>
            </setting>
            <setting name="FirmwareFilePath" serializeAs="String">
                <value>test</value>
            </setting>
        </HawkConfigGUI.Properties.Settings>
    </userSettings>
</configuration>

Then you Import the file and all of the settings are changed in the app (don't forget to .Save() at some point). If something goes wrong, the settings will revert back.

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

namespace HawkConfigGUI
{
    public static class SettingsIO
    {
        private static NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();

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

            var appSettings = Properties.Settings.Default;
            try
            {
                // Open settings file as XML
                var import = XDocument.Load(settingsFilePath);
                // Get the <setting> elements
                var settings = import.XPathSelectElements("//setting");
                foreach (var setting in settings)
                {
                    string name = setting.Attribute("name").Value;
                    string value = setting.XPathSelectElement("value").FirstNode.ToString();

                    try
                    {
                        appSettings[name] = value; // throws SettingsPropertyNotFoundException
                    }
                    catch (SettingsPropertyNotFoundException spnfe)
                    {
                        _logger.WarnException("An imported setting ({0}) did not match an existing setting.".FormatString(name), spnfe);
                    }
                    catch (SettingsPropertyWrongTypeException typeException)
                    {
                        _logger.WarnException(string.Empty, typeException);
                    }
                }
            }
            catch (Exception exc)
            {
                _logger.ErrorException("Could not import settings.", exc);
                appSettings.Reload(); // from last set saved, not defaults
            }
        }

        internal static void Export(string settingsFilePath)
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            config.SaveAs(settingsFilePath);
        }
    }
}
Pat
I would like to know why someone considers this a bad answer as well as have somebody produce a "good" answer. All I have to say is that this code *works* and there have been no other working solutions presented.
Pat
By the way, this solution *does not* manipulate the app.config file. It modifies the in-memory version of user.config which is transferred to file on application close.
Pat
A: 

Since I did not receive any other answers and was not happy with my previous solution, I asked the question again, did some more research, and was able to come up with a better answer. See How to load a separate Application Settings file dynamically and merge with current settings? for the code and explanation.

Pat