Search code examples
.netapp-confignamevaluecollection

Modifying config sections in App.config either at runtime or install time


I have an WinForms application that is deployed using Visual Studio 2008's publish (ClickOnce) system. Within the application's app.config file I have a config section that is required by a third party component that has the form:

<section name="thirdPartySection"
type="System.Configuration.NameValueSectionHandler" />

The section is thus not in the appSettings and looks like:

<thirdPartySection >
  <add key="someKey" value="someValue" />
</thirdPartySection >

I understand that the key/value pairs are a NameValueCollection. The problem I face is that I wish to change the value either a deployment time or at runtime (either is fine with me) so that someValue will be someOtherValue based on the environment installed in.

Currently I make some other config changes at runtime, but those are in the AppSettings section, and thus easy to get at. I have found many references in my search for a solution, but they seem to rely on the section having a custom class, not the NameValueCollection that I'm faced with.

Does anyone know the best way to modify this data? A runtime change with a ConfigurationManager.RefreshSection() would be more in line with my current code, but I'm open to suggestions during the install phase as well.

Edit: This works at runtime. This is how I was handling the old configuration overrides.

Configuration config = ConfigurationManager.OpenExeConfiguration(
    ConfigurationUserLevel.None);

config.AppSettings.Settings["Main.ConnectionString"].Value = 
    PolicyTrackerInfo.ConnectionString;

config.AppSettings.Settings["Main.linq"].Value = 
    PolicyTrackerInfo.LinqConnectionString;


config.Save(ConfigurationSaveMode.Modified);

ConfigurationManager.RefreshSection("appSettings");

My attempt to do the same for another section:

string overwriteXml = config.GetSection("thirdPartySection")
    .SectionInformation.GetRawXml();

XmlDocument xml = new XmlDocument();
xml.LoadXml(overwriteXml);
XmlNode node = xml.SelectSingleNode("thirdPartySection/add");
node.Attributes["value"].Value = PolicyTrackerInfo.OverwriteString;

So far, so good. However, I don't see a method that allows me to replace the old XML with my modified data. Is it possible at runtime?

As an aside: I tried modifying the app.config.deploy file by hand. That just gives me a validation error as the modification is detected by the installer and it refuses to proceed. I really like the auto deploy, and the prior override worked great.


Solution

  • One thing you could do is add a first-time-running section to your code that does additional setup, such as modifying the application config file. To detect whether this setup needs to be done, your third-party config section could come pre-populated with dummy values that your application would recognize as belonging to a new install. For example, your config file could look like this:

    <thirdPartySection>
        <add key="someKey" value="#NEEDS_INITIALIZED#" />
    </thirdPartySection >
    

    And your Main method could look something like this:

    static public void Main(params string[] args)
    {
        const string uninitializedValue = "#NEEDS_INITIALIZED#";
    
        // Load the third-party config section (this assumes it inherits from
        // ConfigurationElementCollection
        var config = ConfigurationManager.OpenExeConfiguration(
            ConfigurationUserLevel.None);
        var section = config.GetSection("thirdPartySection") 
            as NameValueConfigurationCollection;
        var setting = section["someKey"];
        if (setting.Value == uninitializedValue)
        {
            setting.Value = PolicyTrackerInfo.OverwriteString;
            config.Save();
        }
    }