Load configuration from a file and handling file´s changes
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
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.
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);
}
}