Shimrit Hadadi
Shimrit Hadadi

Reputation: 115

I keep getting exception sometimes on System.Threading.Tasks.TaskCompletionSource<bool> how can i solve it?

I have a watcher method i'm calling from the constructor of fomr1:

FileSystemWatcher watcher;
        private void WatchDirectory()
        {
            watcher = new FileSystemWatcher();
            watcher.Path = userVideosDirectory;
            watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
            watcher.Filter = "*.mp4";
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.EnableRaisingEvents = true;
        } 

Then the Onchanged event:

private void OnChanged(object source, FileSystemEventArgs e)
        {

                var info = new FileInfo(e.FullPath);
                fileforupload = info.FullName;
                if (IsFileLocked(info) == false)
                {
                    sy.SetResult(true);
                    watcher.EnableRaisingEvents = false;
                    watcher.Dispose();
                }
        }

And this is the IsFileLocked method:

protected virtual bool IsFileLocked(FileInfo file)
        {
            FileStream stream = null;
            try
            {
                stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException)
            {
                return true;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }

And i'm using it in this method:

public string SendResponse(HttpListenerRequest request)
        {            
                    sy = new TaskCompletionSource<bool>();
                    WatchDirectory();
                    sy.Task.Wait();
                    Youtube_Uploader youtubeupload = new Youtube_Uploader(fileforupload);
                    return false;
        }

The exception is in the OnChanged event on the line:

sy.SetResult(true);

sy is:

TaskCompletionSource<bool> sy;

In the OnChanged method i did:

watcher.EnableRaisingEvents = false;
watcher.Dispose();

But still getting sometimes the exception. The exception is:

An attempt was made to transition a task to a final state when it had already completed

System.InvalidOperationException was unhandled
  _HResult=-2146233079
  _message=An attempt was made to transition a task to a final state when it had already completed.
  HResult=-2146233079
  IsTransient=false
  Message=An attempt was made to transition a task to a final state when it had already completed.
  Source=mscorlib
  StackTrace:
       at System.Threading.Tasks.TaskCompletionSource`1.SetResult(TResult result)
       at Automatic_Record.Form1.OnChanged(Object source, FileSystemEventArgs e) in d:\C-Sharp\Automatic_Record\Automatic_Record\Automatic_Record\Form1.cs:line 197
       at System.IO.FileSystemWatcher.OnChanged(FileSystemEventArgs e)
       at System.IO.FileSystemWatcher.NotifyFileSystemEventArgs(Int32 action, String name)
       at System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* overlappedPointer)
       at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
  InnerException: 

Upvotes: 1

Views: 2336

Answers (1)

Deepak Bhatia
Deepak Bhatia

Reputation: 1100

This is happening because FileSystemWatcher fire multiple onChanged event for any single change. So before you disable EnableRaisingEvent watcher could have fired multiple onChanged event. You need to put locking in your onChanged method or instead of using TaskCompletionSource.SetResult use TaskCompletionSource.TrySetResult.

See this for details on TrySetResult: https://msdn.microsoft.com/en-us/library/dd449176(v=vs.110).aspx

Upvotes: 3

Related Questions