{"id":55909,"date":"2010-05-04T22:37:00","date_gmt":"2010-05-04T22:37:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2010\/05\/04\/parallelextensionsextras-tour-16-async-tasks-for-webclient-smtpclient-and-ping\/"},"modified":"2010-05-04T22:37:00","modified_gmt":"2010-05-04T22:37:00","slug":"parallelextensionsextras-tour-16-async-tasks-for-webclient-smtpclient-and-ping","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/parallelextensionsextras-tour-16-async-tasks-for-webclient-smtpclient-and-ping\/","title":{"rendered":"ParallelExtensionsExtras Tour &#8211; #16 &#8211; Async Tasks for WebClient, SmtpClient, and Ping"},"content":{"rendered":"<p><p><span style=\"font-size: small\"><span style=\"font-family: Calibri\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\"><\/p>\n<p class=\"MsoNormal\"><em><span><span style=\"font-size: small\">(The full set of ParallelExtensionsExtras Tour posts is available <a href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2010\/04\/04\/9990342.aspx\"><span style=\"color: #dd4a21\">here<\/span><\/a><\/span><\/span><\/em><span style=\"font-size: small\"><em><span>.)<\/span><\/em><\/span><\/p>\n<p><span style=\"font-size: small\"><span style=\"font-family: Calibri\"><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"font-size: small\"><span style=\"font-family: Calibri\"><\/span><\/span><\/p>\n<p><span style=\"font-size: small\"><span style=\"font-family: Calibri\">The Task Parallel Library isn&rsquo;t just about CPU-bound operations.<span>&nbsp; <\/span>The Task class is a great representation for any asynchronous operation, even those implemented purely as asynchronous I\/O.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-family: Calibri;font-size: small\">Task&rsquo;s ability to represent arbitrary asynchronous operations without tying up threads is rooted in the TaskCompletionSource&lt;TResult&gt; class (previously discussed <\/span><a href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2009\/06\/02\/9685804.aspx\"><span style=\"font-family: Calibri;font-size: small\">here<\/span><\/a><span style=\"font-family: Calibri;font-size: small\">), and this becomes a building block for creating an unlimited number of higher-level asynchronous operations represented as a Task. <\/span><a href=\"https:\/\/code.msdn.microsoft.com\/ParExtSamples\"><span style=\"font-family: Calibri;font-size: small\">ParallelExtensionsExtras<\/span><\/a><span style=\"font-family: Calibri;font-size: small\"> includes a wealth of such implementations, and for the next several blog posts in this <\/span><a href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2010\/04\/04\/9990342.aspx\"><span style=\"font-family: Calibri;font-size: small\">ParallelExtensionsExtras Tour<\/span><\/a><span style=\"font-size: small\"><span style=\"font-family: Calibri\"> series, we&rsquo;ll examine several implementations as well as how they can be used in your own projects that require asynchrony.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-size: small\"><span style=\"font-family: Calibri\">The ParallelExtensionsExtrasExtensionsEAP folder contains three useful files: WebClientExtensions.cs, SmtpClientExtensions.cs, and PingExtensions.cs.<span>&nbsp; <\/span>As you might guess, these files contain extension methods for the System.Net.WebClient, System.Net.Mail.SmtpClient, and System.Net.NetworkInformation.Ping classes.<span>&nbsp; <\/span>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.<span>&nbsp; <\/span>For example, WebClientExtensions provides the following method, which will download the data at the specified address and return a Task&lt;byte[]&gt; to represent the result:<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>public<\/span><span> <span>static<\/span> <span>Task<\/span>&lt;<span>byte<\/span>[]&gt; DownloadDataTask(<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>this<\/span> <span>WebClient<\/span> webClient, <span>string<\/span> address);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\">&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span style=\"font-size: small\"><span style=\"font-family: Calibri\">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&nbsp;operation asynchronously only when all of the asynchronous downloads have completed, in this case outputting some diagnostic information about each download&rsquo;s success or failure, e.g.<\/p>\n<p><\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\">&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Task<\/span><span>.Factory.ContinueWhenAll(<span>new<\/span>[]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>new<\/span> <span>WebClient<\/span>().DownloadDataTask(<span>&#8220;http:\/\/www.microsoft.com&#8221;<\/span>),<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>new<\/span> <span>WebClient<\/span>().DownloadDataTask(<span>&#8220;https:\/\/blogs.msdn.com\/pfxteam&#8221;<\/span>),<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>new<\/span> <span>WebClient<\/span>().DownloadDataTask(<span>&#8220;https:\/\/msdn.com\/concurrency&#8221;<\/span>)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>},<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>tasks =&gt;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>\/\/ All tasks completed; look at the result for each<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>foreach<\/span> (<span>var<\/span> task <span>in<\/span> tasks)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>\/\/ Print out information about each download<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Console<\/span>.WriteLine(<span>&#8220;Address: &#8220;<\/span> + task.AsyncState);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>if<\/span> (task.IsFaulted) <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><span>Console<\/span><span>.WriteLine(<span>&#8220;tFailed: {0}&#8221;<\/span>, <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><span>task.Exception.InnerException.Message);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>else<\/span> <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Console<\/span>.WriteLine(<span>&#8220;tDownloaded {0} bytes&#8221;<\/span>, <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><span>task.Result.Length);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>});<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\">&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span style=\"font-size: small\"><span style=\"font-family: Calibri\">As another example, the PingExtensions class provides the extension method:<\/p>\n<p><\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\">&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>public<\/span> <span>static<\/span> <span>Task<\/span>&lt;<span>PingReply<\/span>&gt; SendTask(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>this<\/span> <span>Ping<\/span> ping, <span>string<\/span> hostNameOrAddress);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\">&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span style=\"font-size: small\"><span style=\"font-family: Calibri\">This makes it easy to send multiple pings asynchronously and work with the resulting task objects, e.g.<\/p>\n<p><\/span><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\">&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>var<\/span><span> addresses = <span>new<\/span>[] <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>&#8220;localhost&#8221;<\/span>,<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>&#8220;microsoft.com&#8221;<\/span>,<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>&#8220;msdn.com&#8221;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>};<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>var<\/span><span> pings = (<span>from<\/span> address <span>in<\/span> addresses <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span>select<\/span><span> <span>new<\/span> <span>Ping<\/span>().SendTask(address)).ToArray();<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>foreach<\/span><span> (<span>var<\/span> ping <span>in<\/span> pings)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>\/\/ Print out each ping as it succeeds or fails<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>ping.ContinueWith(t =&gt;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Console<\/span>.WriteLine(<span>&#8220;Ping for {0}: {1}&#8221;<\/span>, t.AsyncState, <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>t.IsFaulted ? <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>t.Exception.InnerException.Message : <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>t.Result.Status.ToString());<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span>});<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><\/span>&nbsp;<\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><\/span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\"><\/p>\n<p class=\"MsoNormal\">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.<\/p>\n<p class=\"MsoNormal\"><span>var<\/span><span> pings = (<span>from<\/span> address <span>in<\/span> addresses <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span>select<\/span><span> <span>new<\/span> <span>Ping<\/span>().SendTask(address)).ToArray();<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Task<\/span><span>.Factory.ContinueWhenAny(<\/span><span><span>pings<\/span><\/span><span>, <\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;&nbsp;&nbsp; <\/span><span>ping =&gt; <span>Console<\/span>.WriteLine(<\/span><span><span>&#8220;First ping completed: &#8220;<\/span> + ping.Result.Address));<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\"><\/p>\n<p><span style=\"font-family: Calibri;font-size: small\"><\/p>\n<p class=\"MsoNormal\">In our next post, we&rsquo;ll continue our exploration of using tasks for asynchrony.<\/p>\n<p><\/span><\/p>\n<p><\/span><\/p>\n<p><\/span><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>(The full set of ParallelExtensionsExtras Tour posts is available here.) The Task Parallel Library isn&rsquo;t just about CPU-bound operations.&nbsp; The Task class is a great representation for any asynchronous operation, even those implemented purely as asynchronous I\/O. Task&rsquo;s ability to represent arbitrary asynchronous operations without tying up threads is rooted in the TaskCompletionSource&lt;TResult&gt; class (previously [&hellip;]<\/p>\n","protected":false},"author":360,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7907,7909,7924,7912],"class_list":["post-55909","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-net-4","tag-parallel-extensions","tag-parallelextensionsextras","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>(The full set of ParallelExtensionsExtras Tour posts is available here.) The Task Parallel Library isn&rsquo;t just about CPU-bound operations.&nbsp; The Task class is a great representation for any asynchronous operation, even those implemented purely as asynchronous I\/O. Task&rsquo;s ability to represent arbitrary asynchronous operations without tying up threads is rooted in the TaskCompletionSource&lt;TResult&gt; class (previously [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55909","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/360"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=55909"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/55909\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=55909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=55909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=55909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}