I am implementing a downloader class and i am using Tasks, first i created a task and passed the CancellationToken with it, when i cancel the task, the Task is canceled but the status of the task is still Running, even after i call ThrowIfCancellationRequested() the staus is still the same. Isn't the status suppose to be Canceled or Faulted in case i throw the ThrowIfCancellationRequested().
Here is my code:
public void Start()
{
//Start download
Status = DownloadStatus.Running;
CancellTS = new CancellationTokenSource();
CancelT = CancellTS.Token;
TaskStartDownload = Task.Run(() => { StartDownload(); }, CancelT);
}
private void StartDownload()
{
//Raise event download start
if (OnDownloadStart != null)
OnDownloadStart(this, new DownloadEventArgs(Id, 0, 0, 0, Controls, false));
byte[] buffer = new byte[4096];
long bytesToRead = Size;
Timer.Start();
while (!CancelT.IsCancellationRequested)
{
int currentBytesRead = Reader.Read(buffer, 0, buffer.Length);
Speed = currentBytesRead == 0 ? 0 : ((float)BytesRead / 1024) / Timer.Elapsed.TotalSeconds;
ProgressPercentage = ProgressPercentage + (currentBytesRead * 1.0 / Size) * 100;
TimeRemaining = (int)(((double)(Size - BytesRead) / 1024) / Speed);
if (currentBytesRead == 0)
{
Status = DownloadStatus.Completed;
//Raise event download start
if (OnDownloadComplete != null)
OnDownloadComplete(this, new DownloadEventArgs(Id, 100, 0, 0, Controls, false));
break;
}
Writer.Write(buffer, 0, currentBytesRead);
Writer.Flush();
//Raise progress event
this.OnDownloadProgress(this, new DownloadEventArgs(Id, Speed, ProgressPercentage, TimeRemaining, Controls, false));
BytesRead += currentBytesRead;
if (Status == DownloadStatus.Pause || Status == DownloadStatus.Cancel)
break;
}
Timer.Stop();
Reader.Close();
Reader = null;
Writer.Close();
if (CancelT.IsCancellationRequested)
{
try
{
CancelT.ThrowIfCancellationRequested();
}
catch (Exception ex)
{
Status = DownloadStatus.Cancel;
//Raise event download start
if (OnDownloadCancel != null)
this.OnDownloadCancel(this, new DownloadEventArgs(Id, 0, 0, 0, Controls, true));
File.Delete(FileNameWithPath);
}
}
TaskPrepareDownload.Dispose();
TaskStartDownload.Dispose();
}
public void Cancel()
{
if (TaskStartDownload == null)
{
return;
}
else
{
CancellTS.Cancel();
}
}
You should not Swallow the exception after you call ThrowIfCancellationRequested(), so the caller (the Start() method) can be notified of the change in task status. If you swallow the exception, the task is considered to be successfully completed (Status = RanToCompletion), or still Running if you poll it immediately after you fire the cancellation.
The exception handler should be placed in the caller when you wait for task to be completed.
Please refer to the example from MSDN Task Cancellation.