7
votes

I am writing a configuration system in which the app.config file is dynamically constructed from various config fragments distributed across multiple locations. The system currently works as follows:

  1. Bootstrapper builds configuration file.
  2. Bootstrapper initializes new AppDomain with new config file as the configuration file.
  3. As a result, new AppDomain is configured to use new config file and all works fine.

We'd like to move away from this multiple AppDomain approach; it adds a layer of complexity, especially when it comes to unmanaged libraries and other legacy code.

In moving to one AppDomain, the workflow would change to:

  1. Bootstrapper builds configuration file.
  2. Bootstrapper merges the configuration file into its own configuration file.
  3. Bootstrapper refreshes its ConfigurationManager cache.
  4. Bootstrapper launches main app in the same AppDomain.

It seems that the ConfigurationManager caches sections in memory. So for example, if I read the AppSettings before step #3, I have to call: ConfigurationManager.RefreshSection("appSettings"); In fact, I have to make sure that any section that has been used by the bootstrapper, is refreshed.

I am able to iterate over all of the config sections in the new config file and force refresh them, but, this forces the configuration manager to load any assemblies referenced in the config file. I'd like to defer this if possible. If there a way to invalidate what the ConfigurationManager currently has in memory?

1

1 Answers

0
votes

I know the question was posted a long time ago but I hope this answer will still be useful.

It seems there is no standard way to do this. However, by accessing internal fields and types of the ConfigurationManager class I was able to list all loaded sections. This is how I did it :

private static IEnumerable<string> GetLoadedSections()
{
    // s_configSystem can be null if the ConfigurationManager is not properly loaded. Accessing the AppSettings *should* do the trick.
    var appSettings = ConfigurationManager.AppSettings;

    FieldInfo s_configSystemField = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic | BindingFlags.Static);
    object s_configSystem = s_configSystemField.GetValue(null);
    FieldInfo _completeConfigRecordField = s_configSystem.GetType().GetField("_completeConfigRecord", BindingFlags.NonPublic | BindingFlags.Instance);
    object _completeConfigRecord = _completeConfigRecordField.GetValue(s_configSystem);
    FieldInfo _sectionRecordsField = _completeConfigRecord.GetType().GetField("_sectionRecords", BindingFlags.NonPublic | BindingFlags.Instance);
    Hashtable _sectionRecords = (Hashtable)_sectionRecordsField.GetValue(_completeConfigRecord);
    return _sectionRecords.Keys.OfType<string>();
}

The "system.diagnostics" section seems to always be loaded. The "appSettings" section is also loaded since I have to access it to make it work consistently.

This works on my machine (.NET 4.5) but since it relies on internal stuff, it can break at any time if Microsoft decide to change the implementation of the ConfigurationManager class.