ParallelExtensionsExtras Tour - #16 - Async Tasks for WebClient, SmtpClient, and Ping

ParallelExtensionsExtras Tour - #16 - Async Tasks for WebClient, SmtpClient, and Ping

  • Comments 7

(The full set of ParallelExtensionsExtras Tour posts is available here.)

The Task Parallel Library isn’t just about CPU-bound operations.  The Task class is a great representation for any asynchronous operation, even those implemented purely as asynchronous I/O.

Task’s ability to represent arbitrary asynchronous operations without tying up threads is rooted in the TaskCompletionSource<TResult> class (previously discussed here), and this becomes a building block for creating an unlimited number of higher-level asynchronous operations represented as a Task. ParallelExtensionsExtras includes a wealth of such implementations, and for the next several blog posts in this ParallelExtensionsExtras Tour series, we’ll examine several implementations as well as how they can be used in your own projects that require asynchrony.

The ParallelExtensionsExtras\Extensions\EAP\ folder contains three useful files: WebClientExtensions.cs, SmtpClientExtensions.cs, and PingExtensions.cs.  As you might guess, these files contain extension methods for the System.Net.WebClient, System.Net.Mail.SmtpClient, and System.Net.NetworkInformation.Ping classes.  These extension methods mirror the existing asynchronous methods on these types (which all implement the Event-Based Asynchronous Pattern), but rather than forcing you to first register for some events and then call a method to kick off the download, they simply return task-based representations.  For example, WebClientExtensions provides the following method, which will download the data at the specified address and return a Task<byte[]> to represent the result:

public static Task<byte[]> DownloadDataTask(

    this WebClient webClient, string address);

 

With a method like this, you can very easily download a single file, but you can now also take advantage of the power of the Task class to, for example, download multiple files and perform a follow-up operation asynchronously only when all of the asynchronous downloads have completed, in this case outputting some diagnostic information about each download’s success or failure, e.g.

 

Task.Factory.ContinueWhenAll(new[]

{

    new WebClient().DownloadDataTask("http://www.microsoft.com"),

    new WebClient().DownloadDataTask("http://blogs.msdn.com/pfxteam"),

    new WebClient().DownloadDataTask("http://msdn.com/concurrency")

},

tasks =>

{

    // All tasks completed; look at the result for each

    foreach (var task in tasks)

    {

        // Print out information about each download

        Console.WriteLine("Address: " + task.AsyncState);

        if (task.IsFaulted)

            Console.WriteLine("\tFailed: {0}",

                task.Exception.InnerException.Message);

        else

            Console.WriteLine("\tDownloaded {0} bytes",

                task.Result.Length);

    }

});

 

As another example, the PingExtensions class provides the extension method:

 

    public static Task<PingReply> SendTask(
        this Ping ping, string hostNameOrAddress);

 

This makes it easy to send multiple pings asynchronously and work with the resulting task objects, e.g.

 

var addresses = new[]

{

    "localhost",

    "microsoft.com",

    "msdn.com"

};

 

var pings = (from address in addresses

             select new Ping().SendTask(address)).ToArray();

foreach (var ping in pings)

{

    // Print out each ping as it succeeds or fails

    ping.ContinueWith(t =>

    {

        Console.WriteLine("Ping for {0}: {1}", t.AsyncState,

            t.IsFaulted ?

                t.Exception.InnerException.Message :

                t.Result.Status.ToString());

    });

}

 

Or by taking advantage of the ContinueWhenAny method, we can send out several pings and take action just when the first ping completes, e.g.

var pings = (from address in addresses

             select new Ping().SendTask(address)).ToArray();

Task.Factory.ContinueWhenAny(pings,

    ping => Console.WriteLine("First ping completed: " + ping.Result.Address));

 

In our next post, we’ll continue our exploration of using tasks for asynchrony.

Leave a Comment
  • Please add 4 and 3 and type the answer here:
  • Post
  • Where's the download for the WebClient Async Tasks ?

  • Hi Luka-

    Such extensions are available as part of our .NET 4 samples at code.msdn.microsoft.com/ParExtSamples, as well as built into the Async CTP available for download from http://msdn.com/vstudio/async.

  • Hi there,

    I working on  a program that spiders the web for images ant it seem that your code above could speed up things a bit.

    On question, in the continuation task i need to know what type of Content-Type was returned for a particular task, is it possible?

    Could you guide me in the right direction how this would be done?

    Cheers Niclas

  • Niclas, if you need that level of control, you can use HttpWebRequest/Response or the new HttpClient type in .NET 4.5.  Both of those provide asynchronous capabilities and support providing content-type information.

  • Hey

    I may be missing something basic but howcome does this method:

    namespace System.Net

    {

       public static class WebClientExtensions

       {

           public static Task<byte[]> DownloadDataTask(this WebClient webClient, string address);

    }

    }

    is called like this:

    return new WebClient().DownloadDataTask(url)

  • @huvar: It's an extension method (msdn.microsoft.com/.../bb383977(v=vs.110).aspx)

  • Hi.

    How can I save downloaded files to my harddisk.

    For example I added url of some pictures in web

Page 1 of 1 (7 items)