Friday, December 12, 2014

Async and Await usage

The goal of this post is to explain the usage of async and await keywords, how could be used to convert the existing synchronous method to asynchronous method.

Pre-Requisites:
Working knowledge of Task
Details of what async and await mean can be found in MSDN.

Asynchrony is essential for activities that are potentially blocking, such as when your application accesses the web(or writing big stream to file). Access to a web resource sometimes is slow or delayed. If such an activity is blocked within a synchronous process, the entire application must wait. In an asynchronous process, the application can continue with other work that doesn't depend on the web resource until the potentially blocking task finishes. In this scenario, the usage of wait and async keywords helps to achieve Asynchrony.

Eg: Download the RSS feed from the web asynchronously.
Implementation of this example helps to differentiate the ease of code to achieve Asynchrony with/without async and await keywords.

This could be achieved in 3 ways

Synchronous - UI will be unresponsive until there is no response from the feed server. In the Dot net 4.5 era, nobody will follow this way.

Code snippet to achieve this:

internal static string GetFeed()
{
HttpWebRequest request = HttpWebRequest.Create(@"http://rss.news.yahoo.com/rss/entertainment") as HttpWebRequest;
WebResponse response = request.GetResponse();
Stream responseStream =  response.GetResponseStream();
return new StreamReader(responseStream).ReadToEnd();
}

AsyncCallback - UI will be responsive, but code becomes bulky with extra overhead of callbacks. Before introducing the async and await keywords, this way was very useful to achieve Asynchrony.

Code snippet to achieve this:

internal static void GetFeedUsingAsyncCallback()
        {
 HttpWebRequest request = HttpWebRequest.Create(@"http://rss.news.yahoo.com/rss/entertainment") as HttpWebRequest;
             request.BeginGetResponse(new AsyncCallback(OnGetResponse), request);
        }
  private static void OnGetResponse(IAsyncResult ar)
        {
            HttpWebRequest myHttpWebRequest = ar.AsyncState as HttpWebRequest;
            WebResponse response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(ar);
            // Read the response into a Stream object.
            Stream responseStream = response.GetResponseStream();
            string content = new StreamReader(responseStream).ReadToEnd();

            //Raise event here
        }

Async and Await
·         Responsive UI
·         Clean code
·         Debugging becomes easier as sequential control flow.

Code snippet to achieve this:

 async internal static  Task<string>  GetFeedAsync()
     {
HttpWebRequest request = HttpWebRequest.Create(@"http://rss.news.yahoo.com/rss/entertainment") as HttpWebRequest;
WebResponse response = await request.GetResponseAsync();         
            Stream responseStream = response.GetResponseStream();

            return await new StreamReader(responseStream).ReadToEndAsync();
        }

Assume if Async method is not available, how we will convert it to async method?

async internal static Task<string> GetStringAsyncExtesion(this HttpWebRequest request)
        {
TaskCompletionSource<string> taskCompletionSource = new TaskCompletionSource<string>();

          
                await Task.Run(() =>
                               {
                                  try
                                 {
                                   WebResponse
                                       response = request.GetResponse();

                                   Stream responseStream = response.GetResponseStream();
                                   string result = new StreamReader(responseStream).ReadToEnd();
                                   taskCompletionSource.SetResult(result);
                                    }
                                    catch (Excecption ex)
                                    {
                                        taskCompletionSource.SetException(ex);
                                    }
                               });
           
          
            return await taskCompletionSource.Task;
 }

Use above created new async method as follows:
static internal Task<string> GetStringExplictAsync()
        {
HttpWebRequest request = HttpWebRequest.Create(@"http://rss.news.yahoo.com/rss/entertainment") as HttpWebRequest;

            return request.GetStringAsyncExtesion();
        }
Pl. Provide your comments on this post.