Cfg-NET icon indicating copy to clipboard operation
Cfg-NET copied to clipboard

Load configuration from a file and handling file´s changes

Open ghost opened this issue 6 years ago • 2 comments

Hi,

What do you think about to load the configuration from a file. The best part is that we can watch the file´s changes at runtime and reload the configuration like nJupiter.Configuration (deprecated project). With that, you don´t need to restart the application if any configuration changed or a new configuration was added. I am thinking in somthing like this:

   `public abstract class CfgNode {
    
    ...

    private string CfgFilePath;
    private FileSystemWatcher CfgFileWatcher;
    private readonly object _cfgFileLocker = new object();
    
    ...
    
   public void LoadFromFile(string cfgFilePath)
    {
        if (!File.Exists(cfgFilePath)) throw new ArgumentException($"{nameof(cfgFilePath)} not exists.", nameof(cfgFilePath));

        var configurationsFilePathInfo = new FileInfo(cfgFilePath);

        CfgFileWatcher = new FileSystemWatcher
        {
            Path = configurationsFilePathInfo.DirectoryName,
            Filter = configurationsFilePathInfo.Name,
            NotifyFilter = NotifyFilters.LastWrite
        };

        CfgFileWatcher.Changed += OnCfgFileChanged;

        CfgFileWatcher.EnableRaisingEvents = true;

        CfgFilePath = cfgFilePath;

        var cfg = File.ReadAllText(CfgFilePath);

        Load(cfg);
    }

    private void OnCfgFileChanged(object source, FileSystemEventArgs e)
    {
        try
        {
            lock (_cfgFileLocker)
            {
                CfgFileWatcher.EnableRaisingEvents = false;

                var cfg = File.ReadAllText(CfgFilePath);

                Load(cfg);
            }
        }
        finally
        {
            CfgFileWatcher.EnableRaisingEvents = true;
        }
    }
  
    ...
}`

We will need System.IO.

Regards, Darian

ghost avatar Dec 09 '19 16:12 ghost

Neat idea. I’d like to think about the best way to implement without creating a direct dependency on the file system. Currently you can inject an IReader but it doesn’t have the ability to reload. Maybe an IActiveReader that offers an event that ‘CfgNode’ subscribes to might do the trick.

dalenewman avatar Dec 30 '19 03:12 dalenewman

I've added an integration test here.

I put a pre-release of the file system watcher / reader on nuget here. It targets .netstandard 20. Note: This active reader is disposable since it's internal FileSystemWatcher is disposable.

Beyond the test, I created a throw-away set of console apps (.net framework, and .net core) to try it out. It seems to work fine. I guess one thing to remember is that re-loading the configuration can introduce new errors and/or warnings that you would want to check for in your program.
You can override OnChange on CfgNode to make sure things are okay (e.g.):

      protected override void OnChange(object sender, CfgEventArgs e) {
         Console.WriteLine($"Someone changed me {e.Source}");
         base.OnChange(sender, e);  // the base implementation reloads the configuration
         foreach (var error in Errors()) {
            Console.WriteLine(error);
         }
      }

dalenewman avatar Jan 03 '20 17:01 dalenewman