Robinson
Robinson

Reputation: 10122

Aborting a WebClient.DownloadFileAsync operation

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)

Upvotes: 4

Views: 12114

Answers (1)

Amadeus Hein
Amadeus Hein

Reputation: 716

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();
    }
}

Upvotes: 7

Related Questions