How to create an async method in C# 4 according to the best practices?

c#, parallel-processing, task

Solution

If async related C# 4.0 code is huge and ugly - there is a chance that it's implemented properly. If it's nice and short, then most likely it's not ;)

..though, you may get it look more attractive by creating extension methods on WebRequest, Stream classes and cleanup the main method.

P.S.: I hope C# 5.0 with it's new `async` keyword and library will be released soon.

Reference: http://msdn.microsoft.com/en-us/vstudio/async.aspx

Problem

Consider the following code snippet: ``` public static Task<string> FetchAsync() { string url = "http://www.example.com", message = "Hello World!"; var request = (HttpWebRequest)WebRequest.Create(url); request.Method = WebRequestMethods.Http.Post; return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null) .ContinueWith(t => { var stream = t.Result; var data = Encoding.ASCII.GetBytes(message); Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length, null, TaskCreationOptions.AttachedToParent) .ContinueWith(t2 => { stream.Close(); }); }) .ContinueWith<string>(t => { var t1 = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null) .ContinueWith<string>(t2 => { var response = (HttpWebResponse)t2.Result; var stream = response.GetResponseStream(); var buffer = new byte[response.ContentLength > 0 ? response.ContentLength : 0x100000]; var t3 = Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null, TaskCreationOptions.AttachedToParent) .ContinueWith<string>(t4 => { stream.Close(); response.Close(); if (t4.Result < buffer.Length) { Array.Resize(ref buffer, t4.Result); } return Encoding.ASCII.GetString(buffer); }); t3.Wait(); return t3.Result; }); t1.Wait(); return t1.Result; }); } ``` It should return `Task<string>`, send HTTP POST request with some data, return a result from webserver in a form of string and be as much efficient as possible. - Did you spot any problems regarding async flow in the example above? - Is it OK to have .Wait() inside .ContinueWith() in this example - Do you see any other problems with this peace of code (keeping aside exception handling for now)?

Original source