views:

1192

answers:

3

We just started running in to an odd problem with a FileSystemWatcher where the call to Dispose() appears to be hanging. This is code that has been working without any problems for a while but we just upgraded to .NET3.5 SP1 so I'm trying to find out if anyone else has seen this behavior. Here is the code that creates the FileSystemWatcher:

if (this.fileWatcher == null)
{
   this.fileWatcher = new FileSystemWatcher();
}
this.fileWatcher.BeginInit();
this.fileWatcher.IncludeSubdirectories = true;
this.fileWatcher.Path = project.Directory;
this.fileWatcher.EnableRaisingEvents = true;
this.fileWatcher.NotifyFilter = NotifyFilters.Attributes;
this.fileWatcher.Changed += delegate(object s, FileSystemEventArgs args)
{
   FileWatcherFileChanged(args);
};
this.fileWatcher.EndInit();

The way this is being used is to update the state image of a TreeNode object (adjusted slightly to remove business specific information):

private void FileWatcherFileChanged(FileSystemEventArgs args)
{
   if (this.TreeView != null)
   {
      if (this.TreeView.InvokeRequired)
      {
         FileWatcherFileChangedCallback d = new FileWatcherFileChangedCallback(FileWatcherFileChanged);
         this.TreeView.Invoke(d, new object[]
      {
         args
      });
      }
      else
      {
         switch (args.ChangeType)
         {
            case WatcherChangeTypes.Changed:
               if (String.CompareOrdinal(this.project.FullName, args.FullPath) == 0)
               {
                  this.StateImageKey = GetStateImageKey();
               }
               else
               {
                  projectItemTreeNode.StateImageKey = GetStateImageKey();
               }
               break;
         }
      }
   }
}

Is there something we're missing or is this an anomoly from .NET3.5 SP1?

+2  A: 

Just a thought... Any chance there's a deadlock issue here?

You're calling TreeView.Invoke, which is a blocking call. If a filesystem change happens just as you're clicking whatever button causes the FileSystemWatcher.Dispose() call, your FileWatcherFileChanged method will get called on a background thread and call TreeView.Invoke, which will block until your form thread can process the Invoke request. However, your form thread would be calling FileSystemWatcher.Dispose(), which probably doesn't return until all pending change requests are processed.

Try changing the .Invoke to .BeginInvoke and see if that helps. That may help point you in the right direction.

Of course, it could also be a .NET 3.5SP1 issue. I'm just speculating here based on the code you provided.

Jonathan
A: 

We are also having this issue. Our application runs on .Net 2.0 but is compiled by VS 2008 SP1. I have .NET 3.5 SP1 installed as well. I've got no idea why this happens either, it doesn't look like a deadlock issue on our end as no other threads are running at this point (it is during application shutdown).

Jamie Penney
If you're using a FileSystemWatcher, you are potentially using another thread; the FileSystemWatcher thread could be blocked attempting to invoke on the UI thread.
Judah Himango
+2  A: 

Scott, we've occasionally seen issues with control.Invoke in .NET 2. Try switching to control.BeginInvoke and see if that helps.

Doing that will allow the FileSystemWatcher thread to return immediately. I suspect your issue is somehow that the control.Invoke is blocking, thus causing the FileSystemWatcher to freeze upon dispose.

Judah Himango
This appears to be the case and the correct solution. I awarded the answer to Jonathan as he was the first to respond.
Scott Dorman