Introduction to Async and Await in C# 5.0

This article provides a brief introduction to 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 simplifies 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:

The await keyword may not be inserted into a "lock" code block

With try-catch-finally blocks, await may not be used in the catch or finally sections

Async methods may not use "ref" nor "out" parameters

Class constructors may not be marked async nor may they use the await keyword

Await may only be used in methods marked as async

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 screen shot 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:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace SimpleAsyncAwait

{

classProgram

{

staticvoid Main(string[] args)

{

Console.WriteLine("Starting call to service");

// make a call to a web service using an async method

GetGlobalWeather("Edinburgh", "United Kingdom");

// print out a line to show we are not waiting for the service call to complete

// but rather and pressing on with this main thread

Console.WriteLine("Call in progress...");

// wait for the user to finish reading the report

Console.ReadLine();

}

// since the return type is void, the method has to handle the data itself - so here

// we just dump the data to the screen, error handling has to be implemented

// set a string to the results of the weather query - use await to hold here for the results to

// be returned to the string variable

string weather = await client.GetWeatherAsync(city, country);

// once the string is populated, write it out to the console

Console.WriteLine(weather);

// report completion from the async method

Console.WriteLine("Service call complete");

}

catch (Exception ex)

{

// handle any errors here else risk an unhandled exception

Console.WriteLine("Error: " + ex.Message);

}

finally

{

// tell the user to click a key to close the console window

Console.WriteLine("Press any key to close this window");

}

}

}

}

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.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace AsyncAwait_4

{

classProgram

{

staticvoid Main(string[] args)

{

// tell the user we are going to list available cities

Console.WriteLine("List of Available Cities");

// create a task and assign it to the async call

Task t = GetGlobalWeatherCities("France");

// unlike void, since we have a return type of task, we can do things

// with it like check the status of the operation or wait the task.

Console.WriteLine("Status: " + t.Status.ToString());

// To prove the main thread continunes after the call, write some

// nonsense out the screen whilst the thread runs

WasteTime();

// hold the console open

Console.ReadLine();

}

///<summary>

/// Async call to retrieve a collection of cities available for

/// weather reports

///</summary>

///<param name="country"></param>

///<returns></returns>

staticasyncTask GetGlobalWeatherCities(string country)

{

try

{

// create an instance of the client

GlobalWeather.GlobalWeatherSoapClient client =

new GlobalWeather.GlobalWeatherSoapClient();

// set up a variable to hold the result and use await to hold for the service

// to populate it before pressing on with the task

string cities = await client.GetCitiesByCountryAsync(country);

// once the string variable is populated, print it out to the console

Console.WriteLine(cities);

}

catch (Exception ex)

{

// best to handle the exception here if one is encountered

Console.WriteLine("Error: " + ex.Message);

}

}

///<summary>

/// Waste time drawing out some trash to the

/// console whilst the async method runs out

///</summary>

staticvoid WasteTime()

{

for (int i = 0; i < 50; i++)

{

if(i%2==0)

Console.Write("-");

else

Console.Write("|");

}

Console.WriteLine();

}

}

}

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.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace AsyncAwait_3

{

classProgram

{

staticvoid Main(string[] args)

{

try

{

Console.WriteLine("Fetching Current Edinburgh Weather");

// wx is a placeholder that will be populated through the synchronization context once the method returns

Task<string> wx = GetGlobalWeather("Edinburgh", "United Kingdom");

// display the status of the task

Console.WriteLine("Task Status: " + wx.Status.ToString());

// even though we called the service, this will execute concurrently whilst the async call is in play

// and so the date will be displayed before the weather report

Console.WriteLine(DateTime.Now.ToLongTimeString());

Console.WriteLine("------------------------------------");

// handled when the value returns - this will block on console.writeline until the result returns

// we will await the call to fetch the weather and return the result immediately to the caller

returnawait client.GetWeatherAsync(city, country);

}

}

}

Figure 3 - Console Output for Example 3

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.