Search code examples
c#windows-servicesfilesystemwatcher

FileSystemWatcher as a Windows Service using Visual Studio 2019


So, I have created a windows service, where I use a FileSystemWatcher to watch different directories. Every time changed files are detected I copy them in a different directory, so I can work with them later.

This works perfectly when I run the program as a Console Application.

When I run it as a service, I can start and stop the service properly, but it won't detect any kind of event. I have tried to debug my service and I found out that the error is coming from the fact that I don't stop the FileSystemWatcher.

For my console App, I have this code for the Watch() method:

    public void Watch()
    {
        using (FileSystemWatcher watcher = new FileSystemWatcher($"C:\\Users\\wost\\AppData\\Roaming\\Sublime", _ext))
        {
            watcher.NotifyFilter = NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.FileName
                                 | NotifyFilters.DirectoryName;

            watcher.IncludeSubdirectories = true;
            // Add event handlers.
            watcher.Changed += OnChanged;
            watcher.Created += OnChanged;
            watcher.Deleted += OnChanged;
            watcher.Renamed += OnRenamed;

            // Begin watching.
            watcher.EnableRaisingEvents = true;

            // Wait for the user to quit the program.
            Console.WriteLine("Press 'q' to quit the sample.");
            while (Console.Read() != 'q') ;
        }
    }

So, I stop the program if the user presses 'q'.

For my Windows Service, I have this code for the Watch() method:

 public void Watch()
    {
        using (FileSystemWatcher watcher = new FileSystemWatcher($"C:\\Users\\lashi\\AppData\\Roaming\\Sublime Text 3", _ext))
        {
            watcher.NotifyFilter = NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.FileName
                                 | NotifyFilters.DirectoryName;

            watcher.IncludeSubdirectories = true;
            // Add event handlers.
            watcher.Changed += OnChanged;
            watcher.Created += OnChanged;
            watcher.Deleted += OnChanged;
            watcher.Renamed += OnRenamed;

            // Begin watching.
            watcher.EnableRaisingEvents = true;

        }
    }

So, here I don't stop the FileSystemWatcher at all, because as I don't have a direct interaction with the user, I don't know how to stop it. Can you please help me to find a solution to this?

These are the OnStart() and OnStop() methods:

public partial class Service1 : ServiceBase
{
    Watcher w;
    
    public Service1()
    {
        InitializeComponent();
    }

    protected override void OnStart()
    {
        w = new Watcher($"C:\\EMMC_CACHE\\expt1-log", $"C:\\EMMC_CACHE\\expt1-file", "lashi");
        w.Watch();
    }

    protected override void OnStop()
    {
        DirectoryInfo dir = new DirectoryInfo(@"C:\Users\wost\Desktop\FILES");
        int count = dir.GetFiles().Length;
        // TEST
        if (count == 0)
        {
            StreamWriter writer = new StreamWriter(@"C:\Users\wost\Desktop\Notes.txt");
            writer.WriteLine("Service is stopped at: " + DateTime.Now);
            writer.Close();
        }
    }
}

Solution

  • I think you need to make the watcher a field and not to dispose it prematurely. I didn't test this code but you see the relevant changes in 'Watch', i think....

    internal class Watcher : IDisposable {
    
        private FileSystemWatcher _watcher;
        private string _directoryPath;  
        private string _ext;
        
        internal Watcher (string directoryPath, string ext) {
                _directoryPath = directoryPath;
                _ext = ext;
        }
        ~Watcher () {
            Dispose();
        }
        public void Watch()
        {
            Dispose();
            
            _watcher = new FileSystemWatcher(_directoryPath, _ext);
            
            _watcher.NotifyFilter = NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.FileName
                                 | NotifyFilters.DirectoryName;
    
            _watcher.IncludeSubdirectories = true;
            // Add event handlers.
            _watcher.Changed += OnChanged;
            _watcher.Created += OnChanged;
            _watcher.Deleted += OnChanged;
            _watcher.Renamed += OnRenamed;
    
            // Begin watching.
            _watcher.EnableRaisingEvents = true;
        }
        
         public void Dispose() {
            try {
               _watcher?.Dispose();
            } catch {
               ;
            }
            _watcher = null;
         }
         //FSW event handlers...
    
    }