سؤال

I an creating a sample example to call link using WebClient using async and await method now I want to attach cancel async call functionality also. But I am not able to get CancellationTokenSource token and attach DownloadStringTaskAsync to this cancellation token. Following Is my code can anyone tell me how to accomplish this.

private async void DoWork()
        {
            this.Cursor = Cursors.WaitCursor;
            Write("DoWork started.");
            cts = new CancellationTokenSource();
            WebClient wc = new WebClient();
            string result = await wc.DownloadStringTaskAsync(new Uri("http://gyorgybalassy.wordpress.com"));

            if (result.Length < 100000)
            {
                Write("The result is too small, download started from second URL.");
                result = await wc.DownloadStringTaskAsync(new Uri("https://www.facebook.com/balassy"));
            }
            Write("Download completed. Downloaded bytes: " + result.Length.ToString());
            Write("DoWork ended.");
            this.Cursor = Cursors.Default;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Write("Cancellation started.");
            this.cts.Cancel();
            Write("Cancellation ended.");
        }

When my Cancel button calls cts.Cancel the DownloadStringTaskAsync call is not canceled. Why cancel button is not able to cancel the Async calls?

هل كانت مفيدة؟

المحلول

The async capabilities of WebClient predate .Net 4.5, so it supports the Task-based Asynchronous Pattern only partially. That includes having its own cancellation mechanism: the CancelAsync() method, which works even with the new -TaskAsync methods. To call this method when a CancellationToken is canceled, you can use its Register() method:

cts.Token.Register(wc.CancelAsync);

As an alternative, you could use the new HttpClient, as Stephen suggested, which fully supports TAP, including CancellationTokens.

نصائح أخرى

Extension methods based on svick's answer:

public static async Task<string> DownloadStringTaskAsync(this WebClient webClient, string url, CancellationToken cancellationToken) {
    using (cancellationToken.Register(webClient.CancelAsync)) {
        return await webClient.DownloadStringTaskAsync(url);
    }
}

public static async Task<string> DownloadStringTaskAsync(this WebClient webClient, Uri uri, CancellationToken cancellationToken) {
    using (cancellationToken.Register(webClient.CancelAsync)) {
        return await webClient.DownloadStringTaskAsync(uri);
    }
}

WebClient doesn't support cancellation. I recommend you use a newer type such as HttpClient:

...
cts = new CancellationTokenSource();
string result;
using (var client = new HttpClient())
using (var response = await client.GetAsync("http://gyorgybalassy.wordpress.com", cts.Token))
{
  result = await response.Content.ReadAsStringAsync();
}

if (result.Length < 100000)
...

The GetAsync method by default will not complete until it reads the entire response, so the await response.Content.ReadAsStringAsync line will actually complete synchronously.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top