Search code examples
c#app-config

app.config refresh section not reloading the appsettings section


OK, I hate that there are loads of other posts on this "not working" but given I have spent 3 days trying to get the ConfigurationManager to reload during runtime to prevent restarting my service, I have nowhere else to turn.

I have been using this blog article:

http://dejanstojanovic.net/aspnet/2015/june/auto-realod-application-config-in-net/

to assist me in creating a filewatcher that then reloads the section when the file is saved.

I have modified it to refresh the appSettings section on file change (see code below); however, no matter which way I try, it will not refresh the section and only comes out with the value present at startup.

I have tried:

  • Moving the monitor class from an external project, into the same codebase/project to make sure it wasnt being interfered with as some sort of cross-domain protection business.
  • Adding a separate section into the app.config and reloading that, to ensure it wasnt some .net security based around protecting the appSettings section.
  • renaming appSettings every which way I can to ensure it wasn't a naming problem (read everywhere refreshsection(..) is case sensitive).

Hopefully someone on here can point to where I am being such an idiot!

The code:

public class ConfigMonitor
{
    private readonly FileSystemWatcher _watcher;
    private DateTime _lastChange;

    public ConfigMonitor(string configFilePath)
    {
        if (configFilePath == null)
        {
            throw new ArgumentNullException(nameof(configFilePath));
        }

        _lastChange = DateTime.MinValue;
        configFilePath = string.Concat(System.Reflection.Assembly.GetEntryAssembly().Location, ".config");
        if (File.Exists(configFilePath))
        {
            _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath))
            {
                EnableRaisingEvents = true
            };
            _watcher.Changed += Watcher_Changed;
        }
    }

    ~ConfigMonitor()
    {
        _watcher.EnableRaisingEvents = false;
        _watcher.Changed -= Watcher_Changed;
        _watcher.Dispose();
    }

    public void Stop()
    {
        _watcher.EnableRaisingEvents = false;
        _watcher.Changed -= Watcher_Changed;
        _watcher.Dispose();
    }

    private void Watcher_Changed(object sender, FileSystemEventArgs e)
    {
        if ((DateTime.Now - _lastChange).Seconds <= 5 || IsFileLocked(e.FullPath)) return;
        var monitoredSections = ConfigurationManager.AppSettings["monitoredSections"];

        if (monitoredSections != null)
        {
            IEnumerable<string> sections = monitoredSections.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (sections.Any())
            {
                foreach (var section in sections)
                {
                    ConfigurationManager.RefreshSection(section);
                }
            }
        }
        else
        {
            Debug.WriteLine(ConfigurationManager.AppSettings["TEST"]);
            ConfigurationManager.RefreshSection("appSettings");
            Debug.WriteLine(ConfigurationManager.AppSettings["TEST"]);
        }
        _lastChange = DateTime.Now;
    }

    private bool IsFileLocked(string filePath)
    {
        FileStream stream = null;
        try
        {
            stream = File.OpenRead(filePath);
        }
        catch (IOException)
        {
            return true;
        }
        finally
        {
            stream?.Close();
        }
        return false;
    }
}

Solution

  • Instead of using the static ConfigurationManager, you can try loading a new instance of the configuration.

    var appSettings = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetEntryAssembly().Location).AppSettings;
    string setting = appSettings.Settings[strKeyName].Value;