Thursday, October 11, 2012

Async in C#

C# 5 adds some powerful asynchronous functionality as an expansion to the Task and Task<TResult> aspects of .NET 4.  The old model seemed to focus on the Asynchronous Pattern and the Event-based Asynchronous Pattern but the framework itself didn't bring much to the table for allowing developers with varied levels of knowledge access to an easily adopted methodology.  With the roll out of C# 5, .NET has provided us with a wrapped API for all asynchronous programming via library based method calls.  This is the first building block of the new features for asynchronous programming and it has been said that going forward, all asynchronous operations will work via a method that returns Task or Task<TResult>.

A key change for this version is the addition of the async keyword.  This contextual keyword enables an easy declaration of an asynchronous function. Note that all asynchronous functions must return either void, a Task, or a Task<T>.  When declaring a function with async, it is also required that there must be at least one await expression inside the function itself. 

The await keyword expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off. An await expression can occur only in the body of an immediately enclosing method, lambda expression, or anonymous method that is marked by an async modifier. The term await serves as a keyword only in that context. Elsewhere, it is interpreted as an identifier. Within the method, lambda expression, or anonymous method, an await expression cannot occur in the body of a synchronous function, in a query expression, in the catch or finally block of an exception handling statement, in the block of a lock statement, or in an unsafe context.

// Keyword await used with a method that returns a Task&ltresult&gt.
TResult result = await AsyncMethodThatReturnsTaskTResult();

// Keyword await used with a method that returns a Task.
await AsyncMethodThatReturnsTask();

Here is a simple example, suppose we want to download a webpage as a string so we can check to see if it supports XHTML 1.0,. There is a new method added to WebClient: Task<string> WebClient.DownloadStringTaskAsync(Uri).  Since this returns a Task<string> we can use it within an asynchronous function. We could do this entire process with jsut a few lines of code.

private void button1_Click(object sender, RoutedEventArgs e)
{
   String url = "http://devstorm.blogspot.com";
   String content = await new WebClient().DownloadStringTaskAsync(url);
   textBox1.Text = String.Format("Page {0} supports XHTML 1.0: {1}",
      url, content.Contains("XHTML 1.0"));
}

By adding the async contextual keyword to the method definition, we are able to use the await keyword on our WebClient.DownloadStringTaskAsync method call. This means that when the user clicks the new method (Task<string> WebClient.DownloadStringTaskAsync(string)) is called.  By adding the await keyword, the runtime will call this method that returns Task<string> and execution will return to the UI.  This means that our UI is not blocked while the webpage is downloaded.  Instead, the UI thread will “await” at this point, and let the WebClient do it’s thing asynchronously.  When the WebClient finishes downloading the string, the user interface’s synchronization context will automatically be used to “pick up” where it left off, and the Task<string> returned from DownloadStringTaskAsync is automatically unwrapped and set into the content variable, thus allowing us to report it in the text box.

Notice how the code is obviously shorter and simpler because the initial synchronization context is used to continue the execution of this functionMeaning,  we don’t have to explicitly marshal the call that sets textbox1.Text back to the UI thread, it is just picked up via the framework.  This sort of abstraction of the difficulty is a strong step toward enabling a wide range of developers the ability to leverage asynchronous programming.  The will ultimately, as always, result in better software for the users.