In the Visual Studio 2010 Async CTP, a bunch of extension methods have been added to the WebClient class, to facilitate the “awaiting” of C# 5.0, such as DownloadStringTaskAsync, which can be simply used like so:
- var wc = new WebClient();
- string result = await wc.DownloadStringTaskAsync("http://msdn.microsoft.com");
One of the overloads present in the CTP accepts a CancellationToken, so that the operation could be cancelled by an external CancellationTokenSource. For example:
- async Task<string> GetData(string uri, CancellationToken token) {
- var wc = new WebClient();
- string result = await wc.DownloadStringTaskAsync(new Uri(uri), token);
- return result;
- }
So, the typical caller can use it like so:
- CancellationTokenSource _cts;
-
- private async void OnGetData(object sender, RoutedEventArgs e) {
- var wc = new WebClient();
- _cts = new CancellationTokenSource();
- try {
- string result = await wc.DownloadStringTaskAsync(new Uri("http://www.codevalue.net"), _cts.Token);
- _data.Text = result;
- }
- catch(OperationCanceledException ex) {
- _data.Text = "Cancelled";
- }
- }
Calling CancellationTokenSource.Cancel causes cancellation, delivered as an OperationCancelledExcpetion exception. The actual Cancel would be typically invoked from some event handler:
- private void OnCancel(object sender, RoutedEventArgs e) {
- if(_cts != null)
- _cts.Cancel();
- }
In .NET 4.5, I was expecting the WebClient class to have all the extension methods baked into the type as instance methods. The basic DownloadStringTaskAsync method is there, but with no overload that accepts a CancellationToken. Where did that go?
Well, it turns out that WebClient has lost its attraction. There is a new guy in town – HttpClient. It’s a complete replacement for WebClient (and also HttpWebRequest). It’s built with “async” in mind – all its operations are asynchronous, never synchronous. So, the way to allow cancellation while awaiting is to use HttpClient:
- _cts = new CancellationTokenSource();
- try {
- var result = await client.GetAsync("http://www.codevalue.net", _cts.Token);
- var data = await result.Content.ReadAsStringAsync();
- _data.Text = data;
- _cts.Dispose();
- _cts = null;
- }
- catch(OperationCanceledException ex) {
- _data.Text = "Cancelled";
- }
Note that even getting the actual string is an asynchronous operation (there is a GetStringAsync on HttpClient, but it cannot accept a CancellationToken).
HttpClient is the new HTTP king: it can do anything WebClient and HttpWebRequest can do (plus some more), and all is asynchronous – perfect to use with the new C# 5.0 async feature.