4

What is the best way to cancel a DownloadFileAsync operation safely?

I have a thread (background worker) that kicks off the download and manages other aspects of it and that I end when I see that the thread has CancellationPending == true. After kicking off the download, the thread will sit and spin until the download has completed, or the thread is cancelled.

If the thread is cancelled, I want to cancel the download. Is there a standard idiom for doing this? I've tried CancelAsync, but I get a WebException from it (aborted). I'm not sure this is a clean way of doing the cancel.

Thanks.

Edit: the first exception is and object disposed one on the internal stream (call stack):

System.dll!System.Net.Sockets.NetworkStream.EndRead(System.IAsyncResult asyncResult) System.dll!System.Net.PooledStream.EndRead(System.IAsyncResult asyncResult)

1 Answer 1

7

I'm not sure why you would get an exception from calling CancelAsync.

I use WebClient to handle paralell downloads in our current project, and upon calling CancelAsync the event DownloadFileCompleted is raised by WebClient, where the property Cancelled is true. My event handler looks like this:

private void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        this.CleanUp(); // Method that disposes the client and unhooks events
        return;
    }

    if (e.Error != null) // We have an error! Retry a few times, then abort.
    {
        if (this.retryCount < RetryMaxCount)
        {
            this.retryCount++;
            this.CleanUp();
            this.Start();
        }

        // The re-tries have failed, abort download.
        this.CleanUp();
        this.errorMessage = "Downloading " + this.fileName + " failed.";
        this.RaisePropertyChanged("ErrorMessage");
        return;
     }

     this.message = "Downloading " + this.fileName + " complete!";
     this.RaisePropertyChanged("Message");

     this.progress = 0;

     this.CleanUp();
     this.RaisePropertyChanged("DownloadCompleted");
}

And the cancelling method is simply:

/// <summary>
/// If downloading, cancels a download in progress.
/// </summary>
public virtual void Cancel()
{
    if (this.client != null)
    {
        this.client.CancelAsync();
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for this. I've updated the question to show what I'm getting (right now, I'm first getting an object disposed exception that seems to be coming from the underlying stream). Perhaps I'm Cancelling by not waiting around for completion? I will investigate.
@Robinson Perhaps this might be of interest then: "The Object Disposed exception is thrown, caught and ignored by the WebClient if the file downloads sufficiently fast that progress change events are still being processed after the file has been closed." (reference: stackoverflow.com/questions/3169749/…)
@Robinson You should also note that CancelAsync does not cancel the download instantly, so if you for example dispose objects too early they might be getting an Object Disposed exception because the process hasn't been canceled yet.
Ok Amadeus, I can see you're calling CancelAsync and that you're waiting for the DownloadFileCompleted event. That is what I'm doing too. Mine sets a flag in that method that breaks a spin lock on another thread. Only then does the WebClient get disposed. So I'm kind-of still rubbing my head a little. This happens when I close a form by the way, called from the FormClosing method. It calls Dispose on the object hosting the WebClient, and should wait until its has received the DownloadComplete event before actually disposing.
Ok, I think I'm doing it right but the underlying object is throwing and catching/handling exceptions that VS is reporting to me. I wish I could switch them off just for one object instance :). Anyway as I managed to verify my pattern against yours and it's all good... have some points.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.