Pulling the rug from under Uncle FileSystemWatcher
The FileSystemWatcher class is a nice treat if you need to trace file system modifications (e.g. wait for a file to be created or deleted in a specific path).
The full MSDN documentation gives specs and usage examples.
You will see it's easy to use and still powerful, allowing a variety of scenarios to be monitored. There is one point, though, that I had to painfully find out by messing it up before realizing it was an issue at all.
Imagine the following scenario:
- You are monitoring a network path (UNC or mapped drive), or let's rather say your FileSystemWatcher is.
- The network path becomes unavailable (deleted or unavailable due to network trouble...)
What would you expect? Well, forget about that, because what actually happens is the following: Nothing. Period.Even if the path resurfaces, your FileSystemWatcher is out of its game. That renders it rather useless, because who has a use for a deaf event listener?
Anyway, that's what recently happened within a windows service I've developed. The solution is as plain as good:
FileSystemWatcher offers an Error-event that will be fired in such cases. Subscribe to this event and, in the handler, create a new FileSystemWatcher to listen for events on the original Watcher's path.
Check out the following program, which will watch a path C:\test on your local machine. Once it's running, delete the folder. If you re-create it within 30 seconds (well, 27 really) watching will be resumed, otherwise not.
The full MSDN documentation gives specs and usage examples.
You will see it's easy to use and still powerful, allowing a variety of scenarios to be monitored. There is one point, though, that I had to painfully find out by messing it up before realizing it was an issue at all.
Imagine the following scenario:
- You are monitoring a network path (UNC or mapped drive), or let's rather say your FileSystemWatcher is.
- The network path becomes unavailable (deleted or unavailable due to network trouble...)
What would you expect? Well, forget about that, because what actually happens is the following: Nothing. Period.Even if the path resurfaces, your FileSystemWatcher is out of its game. That renders it rather useless, because who has a use for a deaf event listener?
Anyway, that's what recently happened within a windows service I've developed. The solution is as plain as good:
FileSystemWatcher offers an Error-event that will be fired in such cases. Subscribe to this event and, in the handler, create a new FileSystemWatcher to listen for events on the original Watcher's path.
Check out the following program, which will watch a path C:\test on your local machine. Once it's running, delete the folder. If you re-create it within 30 seconds (well, 27 really) watching will be resumed, otherwise not.
class Program
{
private static FileSystemWatcher fsw;
private static int retryInterval = 3;
private static int maxRetries = 10;
private static int numRetries = 0;
private static bool watcherInstanceCompromised;
[STAThread]
static void Main(string[] args)
{
try
{
Init();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message, e);
throw;
}
}
private static void Init()
{
try
{
fsw = new FileSystemWatcher();
fsw.Path = @"\\127.0.0.1\c$\test";
fsw.Created += OnCreated;
fsw.Error += OnError;
fsw.EnableRaisingEvents = true;
Console.WriteLine("watching {0}", fsw.Path);
numRetries = 0;
watcherInstanceCompromised = false;
}
catch (Exception e)
{
numRetries++;
Console.WriteLine( "could not initialize ({0})", numRetries );
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
}
private static void OnCreated(object source, FileSystemEventArgs f)
{
Console.WriteLine( "file created : {0}", f.FullPath );
}
private static void OnError(object source, ErrorEventArgs e)
{
watcherInstanceCompromised = true;
Console.WriteLine( "error occured." );
fsw.Dispose();
while (numRetries < maxRetries && watcherInstanceCompromised)
{
Console.WriteLine("trying to init after {0} failed attempts", numRetries);
Init();
// sleep for a few seconds
System.Threading.Thread.Sleep(1000 * retryInterval);
}
if (watcherInstanceCompromised)
{
Console.WriteLine( "not back after {0} retries.", numRetries );
}
else
{
Console.WriteLine( "should be working smoothly now" );
}
return;
}
}
Kommentare
Kommentar veröffentlichen