1

I have a custom .config file which is below and wanted to read value of ServerUrl and update it. I can go till AutoUpdate but not sure how can I go to Settings -> ServerUrl.

.Config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <sectionGroup name="AutoUpdate">
      <section name="Settings" type="System.Configuration.NameValueSectionHandler" />
    </sectionGroup>
  </configSections>
  <AutoUpdate>
    <Settings>
      <add key="Enabled" value="True" />
      <add key="ForceActivation" value="True" />
      <add key="Environment" value="Prod" />
      <add key="ServerUrl" value="https://Something.xml" />
      <add key="HourToCheckAutoUpdate" value="1" />
    </Settings>
  </AutoUpdate>
</configuration>

Code:

var configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = @"MyPath\My.config";
var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);

var b = config.GetSectionGroup("AutoUpdate"); // This returns "AutoUpdate".
GThree
  • 2,708
  • 7
  • 34
  • 67
  • 1
    possible duplicate of [Custom app.config section with a simple list of “add” elements](https://stackoverflow.com/a/32637544/6794089) – bman7716 May 15 '18 at 18:30
  • @bman7716 This is not a dup of that question. In your link, the config file is different then mine. I.e. `AppSettingsSection` is used there but not in mine. Also, example has `section -> key` while mime has `section->section->key`. – GThree May 16 '18 at 14:29
  • I see your point, but not for the reason you stated. Your issue isn't with the nested section keys, its the fact you are editing a config file your application doesn't own. I wrote up an answer for you that will get you what you need per your specific circumstances, however, @Stringfellow's answer should be preferred over mine if you can help it. – bman7716 May 17 '18 at 15:25

2 Answers2

2

Update the .Config file to use 'AppSettingsSection':

<section name="Settings" type="System.Configuration.AppSettingsSection" />

Use the following Code to obtain the properties:

var configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = @"MyPath\My.config";
var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);

var settingsSection = (AppSettingsSection) config.GetSection("AutoUpdate/Settings");
var enabled = settingsSection.Settings["Enabled"].Value;
var serverUrl = settingsSection.Settings["ServerUrl"].Value;
Stringfellow
  • 2,788
  • 2
  • 21
  • 36
  • Even if I add `AppSettingsSection` in my config, this doesn't work. `settingsSection` comes null. – GThree May 16 '18 at 14:25
  • Which version of .NET are you using? NameValueSectionHandler seems to be from the days of .NET 1.1. – Stringfellow May 16 '18 at 17:09
  • 1
    @Stringfellow the `NameValueSectionHandler` is still valid, but only if you are working with a configuration file that the running application runs. The signatures differ for `GetSection` between `ConfigurationManager.GetSection` and `ConfigurationManager.OpenMappedExeConfiguration().GetSection()`. The first would allow you to convert/cast the section to a `NameValueCollection` where the second throws a compiler exception. IMO your answer is the preferred way to handle this, but since the config file can't be updated I posted an alternative answer – bman7716 May 17 '18 at 15:34
0

You are going to be limited on what you can do. You aren't going to simply be able to read/convert the section that is flagged with the NameValueSectionHandler in the external config file. The ConfigurationManager.OpenMappedExeConfiguration(...).GetSection(...) method inherits from a difference set of base classes and doesn't know how to handle the NameValueSectionHandler.

The best way to solve this is to flag your section to use the AppSettingsSection instead of the NameValueSectionHandler as detailed in @Stringfellow's answer, however, for whatever reason (probably good ones) you aren't able to do this.

As a result you are going to have to resort to working with the raw xml at some point. Below is an example of how to accomplish this.

// Gets your config section. It won't parse the xml to a 
// key/value structure, but does provide the raw xml
var b = config.GetSection("AutoUpdate/Settings"); 

var rawXml = b.SectionInformation.GetRawXml();

// Get the raw xml value and load it to a queryable XDocument object
var doc = XDocument.Parse(rawXml);
doc.Descendants("add")
    .Single(x => x.Attribute("key").Value == "ServerUrl")
    .SetAttributeValue("value", "http://newthing.xml");

// Set the new xml back to the configuration object and persist the changes
b.SectionInformation.SetRawXml(doc.ToString());
config.Save(ConfigurationSaveMode.Modified, true);

A word of caution doing it this way is that you run a high risk of corrupting your config file(s) by mistake. Again, @Stringfellow's answer would be the preferred way of handling this.

bman7716
  • 693
  • 7
  • 14