Reputation: 1176
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
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
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