C# Config Files: Problems with RefreshSection() in Mono

In which I explore the very basic usage of the .NET Configuration system and hit an apparent bug in Mono’s implementation of it…

As I mentioned in a previous post, I’ve been working a lot recently in MonoDevelop – I’m building a program which can work on any platform (Linux, Mac and Windows) so long as it has the GTK# Runtime installed. This provides a cross-platform windowing toolkit. It takes a bit of getting used to if you’re used to building plain WinForms applications on Windows, but it seems to be working quite well.

One issue I’ve hit (which has nothing to do with GTK# itself) is writing user-specific application configuration out to a config file.

To those of us from the Linux world this is simplicity itself – we’d consider creating a dot-file in the user’s home directory, or, to follow modern conventions, in $XDG_CONFIG_HOME . It’s a bit more complicated in the .NET world though, or at least so the documentation would have you believe.

Essentially if you want simple read only settings for an application, you can store them in an XML-based file called foo.exe.config (assuming your exe is called foo.exe). The file looks something like this:


<?xml version="1.0" encoding="utf-8"?>
<configuration><appSettings>
 <add key="foo" value="300" />
</appSettings></configuration>

You can see there’s a default section called “appSettings” which contains (in this example) a setting with a keyname of “foo” and a value of “300”. These can then easily be read (as strings only) by a basic application such as:


using System;
using System.Configuration;

namespace config_test {
  class Program {
    static void Main(string[] args) {
      string s = ConfigurationManager.AppSettings["foo"];
      Console.WriteLine("Foo = {0}", s);
    }
  }
}

(To run this, make sure your project has a reference to System.Configuration as well – all the modern System Configuration stuff comes in System.Configuration.dll).

As I understand it this simplest version is designed so you can provide a system config file with your application which will be installed alongside the EXE and will, quite possibly, be in a read-only location. So you can perhaps change the program’s behaviour without recompilation. It’s not really designed to store stuff dynamically. It’s because of this reasoning that writing to this section of this file is a bit more complicated.

To write to this appSettings section of this config file (which, as the config file is stored alongside the EXE file, is not really suitable for user specific settings, but for my needs with my current application it will do), one needs to do the following:

Configuration cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
cfg.AppSettings.Settings.Add("foo", "Hello world");
cfg.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");

Note line four above – the call to RefreshSection. By default it seems that the ConfigurationManager caches reads from the config file – if you omit this line, you will only get what you read last time (until your program is restarted), not the last thing you wrote to it. RefreshSection forces the object to re-read the physical file.

So here’s a complete test program:

using System;
using System.Configuration;

namespace config_test {
  class Program {
    static void Main(string[] args) {
      string s = ConfigurationManager.AppSettings["foo"];
      Console.WriteLine("Foo = {0}", s);

      Configuration cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
      cfg.AppSettings.Settings.Add("foo", "Hello world");
      cfg.Save(ConfigurationSaveMode.Modified);
      ConfigurationManager.RefreshSection("appSettings");

      s = ConfigurationManager.AppSettings["foo"];
      Console.WriteLine("Foo = {0}", s);
    }
  }
}

Assuming you are starting with an empty config file , the output on Windows with Visual Studio 2010 gives the following:

Foo = 
Foo = Hello world

However, if you run this on Mono (I’m using MonoDevelop 3.0.3.2) then you get this:

Foo = 
Foo =

The call to RefreshSection doesn’t seem to work. Googling around finds this bug report from three years ago.

The reason I hit this is because every time I open a window in my application I want to read its geometry (width, height, position etc) and restore whatever the user had it set to last time he opened the window.

Of course it’s fairly easy to circumvent by avoiding reading the physical XML file multiple times during the program’s run and just use the config file to persist the settings when the program terminates, but I’m writing this just in case anyone else hits this and doesn’t immediately see what’s going wrong.

Leave a Reply

Your email address will not be published. Required fields are marked *