2

What I'm wanting to do is create a file watcher that is monitoring for any changes in my services config file. When it detects any changes, the service should restart automatically so the changes can get picked up. However, I'm struggling to get the file watcher to notice that any changes have been made.

Here is my watcher code:

private void WatchConfigurationFile(string path)
{
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = path;

    watcher.NotifyFilter = NotifyFilters.LastWrite;
    watcher.Filter = "Project.MyService.exe.config"; // name of the file I'm wanting to watch

    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.EnableRaisingEvents = true;

}

Then for the OnChanged method:

private void OnChanged(object source, FileSystemEventArgs e)
{
    Log.Info("A change in the config has been found. Stopping Service");

    ServiceController service = new ServiceController("MyService");
    try
    {
        TimeSpan timeout = TimeSpan.FromMilliseconds(20);

        service.Stop();
        service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
    }
    catch(Exception ex)
    {
        // ...
        Log.Error("Error restarting service: " + ex.Message);
    }
}

Finally I am calling all of the above with the following call:

public void Run()
{
    WatchConfigurationFile("..\\InstallFolder\\MyService\\");
}

The Run method is already used with in my service. I have the service running on a timer of which Run gets called at the end of each count down. This method already has other method calls in there, so I know that the Run method is working.

What is it I'm doing wrong with? I've got a funny feeling that my path may be incorrect as the config is in the same location as the service itself. But if someone else is able to shed light on this, it would be appreciated.

N0xus
  • 2,674
  • 12
  • 65
  • 126
  • 7
    The watcher is a local variable in `WatchConfigurationFile`, and it's probably garbage collected as soon as the method exits. Refactor it as a member variable. – Gabriel Negut Jan 08 '18 at 14:55
  • @GabrielNegut it's part of my Run method on the service. I'll amend my question – N0xus Jan 08 '18 at 14:59
  • 2
    @N0xus Even if you call that function at the Run method, as Gabriel said `watcher` is local to the function and is being disposed. Declare it at class level and it should work. – Gusman Jan 08 '18 at 15:01
  • You should read some basic c# tutorial that explains how variables, specifically local variables, are treated.You are not keeping a reference to the `FileSystemWatcher`, it doesn't matter at all where the code runs – Camilo Terevinto Jan 08 '18 at 15:05
  • @CamiloTerevinto I know how those things work, it's just my first time using a service. As `watcher` is only used in the one method, which gets called at the end of the timer, I thought it would work. – N0xus Jan 08 '18 at 15:14
  • Well, IT dos not. Move the Timer object to the class scope, should work afterwards – Cleptus Jan 08 '18 at 15:29
  • Similar question here: https://stackoverflow.com/questions/30830565/using-a-filesystemwatcher-with-windows-service/30830791. It's a watcher wrapped in another class and referenced locally in a different service method but it's the same issue I believe. The watcher goes out of scope and gets collected as Gabriel said. Declaring the watcher as a class member keeps it in scope for as long as the service class is in scope. @N0xus: the watcher will work but only for the duration of the Run method which is not long. The watcher gets collected at some point later and then it stops working. – J M Jan 08 '18 at 20:57
  • And here: https://stackoverflow.com/questions/16278783/filesystemwatcher-not-firing-events – J M Jan 08 '18 at 21:04
  • And a great explainer here: https://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage-collection-from-occurring?noredirect=1&lq=1 – J M Jan 08 '18 at 21:05

0 Answers0