Introduction to Async and Await in C# 5.0

Introduction

 
This article provides a brief introduction to the use of Async and Await to make simple asynchronous calls from your C# 5.0/.NET 4.5 applications. Async and Await is a new language feature introduced with the .NET 4.5 update.
 
Async and Await simplify the code necessary to make asynchronous calls; within the mechanization, the compiler manages the complexity whilst the code remains relatively simple. As a developer, you may gain the benefits of this new functionality merely by marking methods using the new keyword "async".
 
Async and await are still open to the same sorts of problems one may encounter coding for asynchronous processing using other approaches, including deadlocks; the complexity of the code is still there, but it is generated for you and you don't need to write it. Whilst the mechanization simplifies the coding it does still require one to be vigilant towards the proper use of the new features.
 

Creating Asynchronous Methods

 
There are three approaches to creating asynchronous methods using the new features; each being defined by its return type:
  • Methods that return void
  • Methods that return Task
  • Methods that return Task<T>
Call Syntax and Error Handling
 
The async keyword marks a method for the compiler. The await keyword signals the code to wait for the return of a long-running operation.
 
Async calls return almost immediately, leaving the main thread responsive whilst the longer-running process is kicked off to run in the background. Use of void returning methods is suitable only for occasions in which the actions completed by the thread are of no further concern to the main thread (for example, if the code is logging an event and the success of the logging task is of no importance to the main thread); void returning methods are suitable for the launch and forget about it sort of scenario. Methods returning Task are similar to void in as much as those methods do not return a value to the calling method either. If data is to be returned to the main thread and handled there, one should use a return type of Task<T>.
 
Error handling within methods using the three return types is different as well. When dealing with void returning methods, the error handling will need to be accomplished in the async method as it will not return to the calling thread. Similarly, Task return type methods should also handle their own errors. Error handling for methods returning Task<T> may be accomplished within the calling thread.
 
Rules for use
 
The following are the rules for use:
  1. The await keyword may not be inserted into a "lock" code block
  2. With try-catch-finally blocks, await may not be used in the catch or finally sections
  3. Async methods may not use "ref" nor "out" parameters
  4. Class constructors may not be marked async nor may they use the await keyword
  5. Await may only be used in methods marked as async
  6. Property accessors may not be marked as async nor may they use await
Example 1 - Void Returning Methods
 
In this example, the main thread will make a call to an async method with a void return type. In this example, an async method will be used to call a web service to fetch a weather report and display it to a console window. The web service used in this example can be found here: http://www.webservicex.net/globalweather.asmx
 
All of the code necessary for this example is contained in the Program.cs file; there is a single void return type async method called by main. The async method is static as well. The code is fully commented so you can follow along with it by reading those comments.
 
The main method calls a void return type async method entitled, "GetGlobalWeather" that accepts a city and country name as its two required arguments. Just to prove the point that the main method is not waiting on the async method to complete, as soon as the call is made, it prints out a message in the console telling the user that the service has been called. If you look at the screenshot in Figure 1, you will see that this message was in fact printed to the screen whilst the service was fetching the weather report, as such, the weather report is actually printed out after the message.
 
When looking over the following code, notice that the error handling was placed into the async method, it would not be possible to catch and process any errors encountered from within the Main method. When using void returning methods, one should always place the error handling directly within the async method.
 
The code for this example is as follows:
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6.    
  7. namespace SimpleAsyncAwait  
  8. {  
  9.     class Program  
  10.     {  
  11.         static void Main(string[] args)  
  12.         {  
  13.             Console.WriteLine("Starting call to service");  
  14.    
  15.             // make a call to a web service using an async method  
  16.             GetGlobalWeather("Edinburgh""United Kingdom");  
  17.    
  18.             // print out a line to show we are not waiting for the service call to complete   
  19.             // but rather and pressing on with this main thread  
  20.             Console.WriteLine("Call in progress...");   
  21.    
  22.             // wait for the user to finish reading the report  
  23.             Console.ReadLine();  
  24.         }  
  25.    
  26.         // since the return type is void, the method has to handle the data itself - so here   
  27.         // we just dump the data to the screen, error handling has to be implemented   
  28.         // here, as well as nothing, is returned to the calling thread  
  29.         static async void GetGlobalWeather(string city, string country)  
  30.         {  
  31.             try  
  32.             {  
  33.                 // create an instance of the client  
  34.                 GlobalWeather.GlobalWeatherSoapClient client = new GlobalWeather.GlobalWeatherSoapClient();  
  35.    
  36.                 // set a string to the results of the weather query - use await to hold here for the results to  
  37.                 // be returned to the string variable  
  38.                 string weather = await client.GetWeatherAsync(city, country);  
  39.    
  40.                 // once the string is populated, write it out to the console  
  41.                 Console.WriteLine(weather);  
  42.    
  43.                 // report completion from the async method  
  44.                 Console.WriteLine("Service call complete");  
  45.             }  
  46.             catch (Exception ex)  
  47.             {  
  48.                 // handle any errors here else risk an unhandled exception  
  49.                 Console.WriteLine("Error:  " + ex.Message);  
  50.             }  
  51.             finally  
  52.             {  
  53.                 // tell the user to click a key to close the console window  
  54.                 Console.WriteLine("Press any key to close this window");  
  55.             }  
  56.         }  
  57.     }  

ConsoleOutput1.jpg
 
Figure 1 - Console Output for Example 1
 
Example 2 - Task Returning Methods
 
In this example, the main thread will make a call to an async method with a Task return type. In this example, an async method will be used to call a web service to fetch a list of cities available for weather reports and display it to a console window. As in the previous example, the web service used in this example can be found here: http://www.webservicex.net/globalweather.asmx
 
All of the code necessary for this example is contained in the Program.cs file; there is a single Task return type async method called by main. The async method is static as well. The code is fully commented so you can follow along by reading those comments.
 
The main method calls a Task return type async method entitled, "GetGlobalWeatherCities" that accepts a country name as its required argument. Once the async method is called, note that we can check the status of the operation (amongst other things). Note also that we can press on with the main thread whilst the async method executes; this is illustrated by printing out some nonsense characters to the console window after calling the method.
 
When looking over the following code, notice too that the error handling was placed into the async method, as with void returning async methods, it is best to handle any errors in the method itself although with the task return type we can monitor and control the thread from main.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6.    
  7. namespace AsyncAwait_4  
  8. {  
  9.     class Program  
  10.     {  
  11.         static void Main(string[] args)  
  12.         {  
  13.             // tell the user we are going to list available cities  
  14.             Console.WriteLine("List of Available Cities");  
  15.    
  16.             // create a task and assign it to the async call  
  17.             Task t = GetGlobalWeatherCities("France");  
  18.    
  19.             //, unlike void, since we have a return type of task, we can do things   
  20.             // with it like check the status of the operation or wait for the task.   
  21.             Console.WriteLine("Status:  " + t.Status.ToString());  
  22.    
  23.             // To prove the main thread continunes after the call, write some  
  24.             // nonsense out the screen whilst the thread runs  
  25.             WasteTime();  
  26.    
  27.             // hold the console open  
  28.             Console.ReadLine();  
  29.         }  
  30.    
  31.         /// <summary>  
  32.         /// Async call to retrieve a collection of cities available for   
  33.         /// weather reports  
  34.         /// </summary>  
  35.         /// <param name="country"></param>  
  36.         /// <returns></returns>  
  37.         static async Task GetGlobalWeatherCities(string country)  
  38.         {  
  39.             try  
  40.             {  
  41.                 // create an instance of the client  
  42.                 GlobalWeather.GlobalWeatherSoapClient client =   
  43.                     new GlobalWeather.GlobalWeatherSoapClient();  
  44.    
  45.                 // set up a variable to hold the result and use await to hold for the service  
  46.                 // to populate it before pressing on with the task  
  47.                 string cities = await client.GetCitiesByCountryAsync(country);  
  48.    
  49.                 // once the string variable is populated, print it out to the console  
  50.                 Console.WriteLine(cities);  
  51.             }  
  52.             catch (Exception ex)  
  53.             {  
  54.                 // best to handle the exception here if one is encountered  
  55.                 Console.WriteLine("Error:  " + ex.Message);  
  56.             }  
  57.         }  
  58.    
  59.         /// <summary>  
  60.         /// Waste time drawing out some trash to the   
  61.         /// console whilst the async method runs out  
  62.         /// </summary>  
  63.         static void WasteTime()  
  64.         {  
  65.             for (int i = 0; i < 50; i++)  
  66.             {  
  67.                 if(i%2==0)  
  68.                     Console.Write("-");  
  69.                 else  
  70.                     Console.Write("|");  
  71.             }  
  72.             Console.WriteLine();  
  73.         }  
  74.     }  

ConsoleOutput2.jpg
 
Figure 2 - Console Output for Example 2
 
Example 3 - Task<T> Returning Methods
 
In this example, the main thread will make a call to an async method with a Task<T> return type. In this example, an async method will be used to call a web service to fetch a weather report and display it to a console window. As in the other examples, the web service used in this example can be found here: http://www.webservicex.net/globalweather.asmx
 
All of the code necessary for this example is contained in the Program.cs file; there is a single Task<T> return type async method called by main. The async method is static as well. The code is fully commented so you can follow along with it by reading those comments.
 
The main method calls a Task<T> return type async method entitled, "GetGlobalWeather" that accepts a city name and a country name as its required arguments. Once the async method is called, note that we can check the status of the operation as we could with the Task return type. Note also that we can press on with the main thread whilst the async method executes; this is illustrated by printing a date string and a line separator to the console window after calling the method. The Task<T> return type async calls will block on the line that actually handles the returned value, in this case, a string containing a weather report.
 
When looking over the following code, notice that the error handling was placed into Main, a departure from how we handled errors on void and Task returning async methods, you may still handle the errors in the async method if you'd like to do that, but you don't need to if you'd rather not.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6.    
  7. namespace AsyncAwait_3  
  8. {  
  9.     class Program  
  10.     {  
  11.         static void Main(string[] args)  
  12.         {  
  13.             try  
  14.             {  
  15.                 Console.WriteLine("Fetching Current Edinburgh Weather");  
  16.    
  17.                 // wx is a placeholder that will be populated through the synchronization context once the method returns  
  18.                 Task<string> wx = GetGlobalWeather("Edinburgh""United Kingdom");  
  19.    
  20.                 // display the status of the task  
  21.                 Console.WriteLine("Task Status:  " + wx.Status.ToString());  
  22.    
  23.                 // even though we called the service, this will execute concurrently whilst the async call is in play  
  24.                 // and so the date will be displayed before the weather report  
  25.                 Console.WriteLine(DateTime.Now.ToLongTimeString());  
  26.                 Console.WriteLine("------------------------------------");  
  27.    
  28.                 // handled when the value returns - this will block on the console.writeline until the result returns  
  29.                 Console.WriteLine(wx.Result);    
  30.             }  
  31.             catch (Exception ex)  
  32.             {  
  33.                 //With Task<T>, we can handle the error in the calling thread  
  34.                 Console.WriteLine("Error: " + ex.Message);  
  35.             }  
  36.             finally  
  37.             {  
  38.                 Console.WriteLine("Operation complete, press any key to terminate session");  
  39.                 Console.ReadLine();  
  40.             }  
  41.         }  
  42.    
  43.         /// <summary>  
  44.         /// An async call returning Task of type string  
  45.         /// </summary>  
  46.         /// <param name="city"></param>  
  47.         /// <param name="country"></param>  
  48.         /// <returns></returns>  
  49.         static async Task<string> GetGlobalWeather(string city, string country)  
  50.         {  
  51.             // note there is no error handling in the async method on this call, that is not to say   
  52.             // one could not put error handling here but in this case it is possible to catch and handle   
  53.             // errors in the calling thread  
  54.             GlobalWeather.GlobalWeatherSoapClient client = new GlobalWeather.GlobalWeatherSoapClient();  
  55.    
  56.             // we will await the call to fetch the weather and return the result immediately to the caller  
  57.             return await client.GetWeatherAsync(city, country);  
  58.         }  
  59.     }  

ConsoleOutput3.jpg
 
Figure 3 - Console Output for Example 3
 
ConsoleOutput4.jpg
 
Figure 4 - An exception handled in the Main, outside the async method
 

Summary

 
In this article, we reviewed the rules for using Async and Await and provided examples of async methods returning void, Task, and Task<T>. The article further addressed some of the issues pertaining to error handling given each of the three potential return types. There is certainly much more to Async and Await than was covered in this simple introduction, and for that matter, with the Task Parallel Library (TPL) in the larger picture.
 
The article does try to illustrate how simple it is to implement this new language feature to make asynchronous calls within your C# 5.0 applications targeting the .NET 4.5 framework.