I am trying to create a windows service to watch the file changes in a specific directory. I am using dotnet core 6 and a BackgroundService
.
I created a separate class named FileMonitor
in which I simply paste the Microsoft FileSystemWatcher
example
public void MyWatcher(string folder)
{
using var watcher = new FileSystemWatcher(folder);
watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName;
watcher.Changed = OnChanged;
watcher.Created = OnCreated;
watcher.Filter = "*.txt";
watcher.EnableRaisingEvents = true;
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
Console.WriteLine($"Changed: {e.FullPath}");
}
private void OnCreated(object sender, FileSystemEventArgs e)
{
string value = $"Created: {e.FullPath}";
Console.WriteLine(value);
}
And in my BackgroundService
I am creating an instance of FileMonitor
and calling the method MyWatcher
as below.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
FileMonitor fm = new FileMonitor();
fm.MyWatcher($"C:\test");
while (!stoppingToken.IsCancellationRequested)
{
}
}
I am not getting any console logs about the file change
CodePudding user response:
using var watcher = new FileSystemWatcher(folder);
That using
right there will dispose of the watcher at the end of that function, so as soon as it sets up the events. They will never get called.
You need to keep the objects alive and rooted for their entire lifetime. Looking at your calling pattern, you should store them in an instance field of type List<FileSystemWatcher>
.
Also your ExecuteAsync
isn't async, despite its name. You need to relinquish your thread at some point, by awaiting either Task.Delay(...)
or Task.Yield()
in your while
loop.
CodePudding user response:
As mentioned, you have a problem that you are disposing the watcher before your task completes.
You also have another issue that your BackgroundTask
is running an infinite loop and will chew through CPU.
For this and other reasons, I recommend you transform this fully into the async
pattern.
public Task MyWatcher(string folder, CancellationToken stoppingToken)
{
var watcher = new FileSystemWatcher(folder)
{
NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName,
Filter = "*.txt",
};
watcher.Changed = OnChanged;
watcher.Created = OnCreated;
watcher.EnableRaisingEvents = true;
var tcs = new TaskCompletionSource();
_ = stoppingToken.Register(() => { watcher.Dispose(); tcs.TrySetResult(); });
return tcs.Task;
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
Console.WriteLine($"Changed: {e.FullPath}");
}
private void OnCreated(object sender, FileSystemEventArgs e)
{
string value = $"Created: {e.FullPath}";
Console.WriteLine(value);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
FileMonitor fm = new FileMonitor();
await fm.MyWatcher($"C:\test", stoppingToken);
}