bobleujr
bobleujr

Reputation: 1176

SystemFileWatcher does not fire events

I've been trying to understand why my FSW isn't firing any events. I instantiate a new object of my below class in my Application_Start and do a WatchFile() but nothing happens =(

public class FileWatcherClass
    {
        private FileSystemWatcher _watcher;
        public void WatchFile(string fileName, string directory)
        {
            // Create a new FileSystemWatcher and set its properties.
            using (_watcher = new FileSystemWatcher(directory, "*.xml"))
            {
                _watcher.NotifyFilter = NotifyFilters.Attributes |
                                        NotifyFilters.CreationTime |
                                        NotifyFilters.FileName |
                                        NotifyFilters.LastAccess |
                                        NotifyFilters.LastWrite |
                                        NotifyFilters.Size |
                                        NotifyFilters.Security;

                // Add event handlers.
                _watcher.Changed +=
                new FileSystemEventHandler(OnChanged);

                // Begin watching.
                _watcher.EnableRaisingEvents = true;

            }
        }

        // Define the event handlers.
        public void OnChanged(object source, FileSystemEventArgs e) { 
            do something..
        }
    }

Upvotes: 0

Views: 77

Answers (2)

Felipe Ramos
Felipe Ramos

Reputation: 305

Here is a slightly more flexible implementation.

Usage:

    static void Main(string[] args)
    {
        using (var watcherManager= new FileSystemWatcherManager())
        {
            watcherManager.OnChangedDetected += (a) =>
            {
                // General event
            };

            watcherManager.RegisterWatcher(@"C:\temp\helloworld");
            watcherManager.RegisterWatcher(@"C:\temp\api-demo", customChangeEvent: (s, e) =>
            {
                // Handle change directly
            });

            Console.ReadKey();
        };
   }

Implementation:

public sealed class FileSystemWatcherManager : IDisposable
{
    private bool _disposed = false;
    private readonly Dictionary<string, FileSystemWatcher> _watchers;
    public delegate void ChangedDetected(FileSystemEventArgs args);
    public event ChangedDetected OnChangedDetected;

    public FileSystemWatcherManager()
    {
        _watchers = new Dictionary<string, FileSystemWatcher>();
    }

    ~FileSystemWatcherManager()
    {
        Dispose(false);
    }

    public FileSystemWatcher RegisterWatcher(string directoryPath, string filter = "*", FileSystemEventHandler customChangeEvent = null)
    {
        if (Directory.Exists(directoryPath))
        {
            if (!_watchers.ContainsKey(directoryPath))
            {
                var watcher = new FileSystemWatcher(directoryPath, filter)
                {
                    EnableRaisingEvents = true,
                    IncludeSubdirectories = true
                };
                watcher.NotifyFilter =  NotifyFilters.Attributes |
                                        NotifyFilters.CreationTime |
                                        NotifyFilters.FileName |
                                        NotifyFilters.LastAccess |
                                        NotifyFilters.LastWrite |
                                        NotifyFilters.Size |
                                        NotifyFilters.Security;

                if (customChangeEvent != null)
                    watcher.Changed += customChangeEvent;
                else
                    watcher.Changed += Watcher_Changed;

                _watchers.Add(directoryPath, watcher);
            }
        }
        else
        {
            throw new InvalidOperationException($"Invalid Directory: {directoryPath}");
        }

        return _watchers.TryGetValue(directoryPath, out FileSystemWatcher value) ? value : null;
    }

    private void Watcher_Changed(object sender, FileSystemEventArgs e)
    {
        OnChangedDetected?.Invoke(e);
    }

    public void Dispose()
    {
        Dispose(true);

        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (_disposed)
        {
            if (disposing)
            {
                foreach(KeyValuePair<string,FileSystemWatcher> pair in _watchers)
                {
                    pair.Value.Dispose();                       
                }

                _watchers.Clear();
            }

            _disposed = true;
        }
    }
}

Upvotes: 0

Etienne de Martel
Etienne de Martel

Reputation: 36852

The issue is with your usage of the using statement:

using (_watcher = new FileSystemWatcher(directory, "*.xml"))

When execution reaches the end of the using block, the watcher is disposed, which means it can no longer raise events.

Remove the using to fix your problem:

_watcher = new FileSystemWatcher(directory, "*.xml");

But that introduces the other issue of never disposing the watcher. An approach would be to implement IDisposable on FileWatcherClass and then dispose the watcher as needed:

public void Dispose()
{
    _watcher?.Dispose(); // if _watcher isn't null, dispose it
}

Then you can just dispose your FileWatcherClass instance when you're done with it.

Upvotes: 5

Related Questions