How to Change .NET Configuration Files at Runtime (including for WCF)
One of the most common issues people run into with WCF configuration, and .NET applications in general, is that configuration files appear to be fixed. You only have one configuration file for an executable, and you can’t use different configuration files as your exe.config while the application is running. Of course, you can always shut down the application, change the configuration, and then restart it with the new configuration file, but that’s tedious and oftentimes undesirable. In this blog post, I’ll show you how to easily get around this limitation.
Suppose you have the following simple configuration file:
<configuration>
<appSettings>
<add key="name" value="foo"/>
</appSettings>
</configuration>
And let’s say you have the following code:
public static void Main()
{
Console.WriteLine(ConfigurationManager.AppSettings["name"]);
ChangeConfiguration();
Console.WriteLine(ConfigurationManager.AppSettings["name"]);
}
static void ChangeConfiguration()
{
Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);
AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("appSettings");
appSettings.Settings.Clear();
appSettings.Settings.Add("name", "bar");
config.Save();
}
The ChangeConfiguration method above opens up the configuration for the currently running executable, clears the appSettings dictionary, and then adds a new entry with value “bar” instead of “foo”. The main method simply checks the value of name before and after changing the configuration. If you run this code as is you’ll get the following output:
foo
foo
So even though you changed the configuration file, you’re not picking up on the appSetting’s new value. This is because the AppSettings section was cached when you first asked for it, and subsequent calls just use the cached version instead of reading from disk.
But now, if you add the following line of code to your Main method:
public static void Main()
{
Console.WriteLine(ConfigurationManager.AppSettings["name"]);
ChangeConfiguration();
ConfigurationManager.RefreshSection("appSettings");
Console.WriteLine(ConfigurationManager.AppSettings["name"]);
}
Making sure to revert the configuration file to its original value “foo”, you get the following output:
foo
bar
So by calling RefreshSection, you’re telling the configuration API that it should invalidate the cached AppSettings section and instead read from disk on the next configuration call.
This is very useful in particular for WCF because it allows you to use different configuration files for different services or clients, and then just have the same application use all of those configuration files. In this way, you avoid having large configuration files that merge together the information for very many services or clients. Unfortunately, you can’t RefreshSection on a section group, only a section, so you’ll typically have to use the following calls to refresh WCF sections:
ConfigurationManager.RefreshSection("system.serviceModel/behaviors");
ConfigurationManager.RefreshSection("system.serviceModel/bindings");
ConfigurationManager.RefreshSection("system.serviceModel/client");
ConfigurationManager.RefreshSection("system.serviceModel/services");
You may have to refresh other sections as well if you’re using some of the more advanced configuration sections.
Also worth noting: you don’t have to use Configuration.Save() to edit a configuration file, like I did above. You can change the file in any way you’d like, including changing the config file manually or using File.Copy().
Comments
Anonymous
January 21, 2010
Thanks Youssef. Not a great fan of .NET style configuration but that's something I did not know and will find an immediate use for. Cheers.Anonymous
January 23, 2010
if the xml of the config gets malformed during external edit, refresh method will raise an exception, and your service will be dead :)Anonymous
January 26, 2010
You're right, liviu. So it's probably a good idea to surround your "new ServiceHost()" call with a try-catch block to make sure the configuration file is valid.Anonymous
June 10, 2010
Hi Youssef, have you actually tried this code in the wcf scenario? I found your and although it looks like a really elegant approach, when I try to create a client proxy class, WCF appears to ignore these calls and still tries to load the endpoint from app.exe.config CheersAnonymous
August 25, 2011
Thank you very much for posting this.