Awaiting Future C# Asynchronous Features Brought to you by .NET Parallel Computing

Introduction

New C# programming feature announcements are always big news. Microsoft recently announced new C# programming features for making asynchronous programming easier. This is good for developer's building applications requiring asynchronous programming, but why venture into asynchronous code if it's not required? The short answer is application users are always looking for a better experience. Look to the adoption of the Graphical User Interface and increasingly more powerful mobile applications for examples of tech savvy consumers demanding a better experience.

Make the skills involved in creating a new user experience more accessible to the average developer and every developer starts incorporating the new user experience into their application. Eventually the new experience is common and not long afterward the new experience becomes a necessity. By making asynchronous coding easier, will this new language feature turn the application responsiveness developers get with asynchronous code into a needed experience?

To help answer that question, using sample code from the "Async CTP", I'm going to walk through the new asynchronous development experience and contrast the development experience with asynchronous code and synchronous code written using current techniques. I'll start with an overview of the sample code.

Sample Overview

Improved User Interface responsiveness is the canonical business case for employing asynchronous code. You'll find the source code for the "Netflix" sample among the resources at the end of the article. As I mentioned earlier this is a Community Technology Preview (CTP). Like all CTPs and Betas, unless explicitly stated, the underlying implementations are subject to change.

A graphic of the sample in action appears below.


Figure 1 Sample in action

As you can see a user enters a year and the application displays all the movies of that year. The code is divided into three samples:

  • A sample developed using the synchronous experience.
  • An asynchronous sample developed using delegates (Actions).
  • An asynchronous sample developed using the new Async features.

As stated earlier, I'll walk through each sample comparing and contrasting the synchronous, current asynchronous and new asynchronous development experience.

Synchronous

The code from the synchronous sample appears below.

  void LoadMovies(int year)
  {
      resultsPanel.Children.Clear();
      cts = new CancellationTokenSource();
      statusText.Text = "";
      var pageSize = 10;
      var imageCount = 0;
      try
      {
          while (true)
          {
              statusText.Text = string.Format("Searching...  {0} Titles", imageCount);
              // (status text doesn't work because the UI never has a breather to show it)
              var movies = QueryMovies(year, imageCount, pageSize, cts.Token);
              if (movies.Length == 0) break;
              DisplayMovies(movies);
              imageCount += movies.Length;
          }
          statusText.Text = string.Format("{0} Titles", imageCount);
      }
      catch (TaskCanceledException)
      {
      }
      cts = null;
  
  }
  
  Movie[] QueryMovies(int year, int first, int count, CancellationToken ct)
  {
      var client = new WebClient();
      var url = String.Format(query, year, first, count);
      var data = client.DownloadString(new Uri(url));
      var movies =
          from entry in XDocument.Parse(data).Descendants(xa + "entry")
          let properties = entry.Element(xm + "properties")
          select new Movie
          {
              Title = (string)entry.Element(xa + "title"),
              Url = (string)properties.Element(xd + "Url"),
              BoxArtUrl = (string)properties.Element(xd + "BoxArt").Element(xd + "LargeUrl")
          };
      return movies.ToArray();
  }

The code above works like you would expect. LoadMovies is the main body of the collection process. Using the WebClient class QueryMovies gathers the movie information into one large XML string, parses the string and creates an array of Movie classes. DisplayMovies renders Bitmaps from the URLs stored in the array of Movie classes.

If you run the synchronous sample, it won't take long before you want to simply cancel it and move on to running the other samples. Far more performant code can be written using asynchronous functions. As stated earlier the first asynchronous sample is written with delegates.



Awaiting Future C# Asynchronous Features Brought to you by .NET Parallel Computing

Async with Delegates

Sample code written using delegates (Actions) appears below.

  void LoadMoviesAsync(int year)
  {
      resultsPanel.Children.Clear();
      cts = new CancellationTokenSource();
      statusText.Text = "";
      var pageSize = 10;
      var imageCount = 0;
      Action<Movie[],Exception> action = null;
      action = (movies,ex) =>
      {
          if (ex != null)
          {
              cts = null;
              if (ex is TaskCanceledException ||
                  (ex is WebException && (ex as WebException).Status == WebExceptionStatus.RequestCanceled))
              {
                  return;
              }
              else
              {
                  throw ex;
              }
          }
  
          statusText.Text = string.Format("Searching...  {0} Titles", imageCount);
          if (movies.Length > 0)
          {
              DisplayMovies(movies);
              imageCount += movies.Length;
              QueryMoviesAsync(year, imageCount, pageSize, cts.Token, action);
          }
          else
          {
              statusText.Text = string.Format("{0} Titles", imageCount);
          }
      };
  
      QueryMoviesAsync(year, imageCount, pageSize, cts.Token, action);
  }
  
  void QueryMoviesAsync(int year, int first, int count, CancellationToken ct, Action<Movie[], Exception> processMovies)
  {
      var client = new WebClient();
      var url = String.Format(query, year, first, count);
  
      ct.Register(delegate
      {
          client.CancelAsync();
      });
  
      client.DownloadStringCompleted += (sender, e) =>
      {
          if (e.Error != null)
          {
              processMovies(null, e.Error);
              return;
          }
          if (e.Cancelled)
          {
              processMovies(null, new TaskCanceledException());
              return;
          }
                  
          var data = e.Result;
          var movies =
              from entry in XDocument.Parse(data).Descendants(xa + "entry")
              let properties = entry.Element(xm + "properties")
              select new Movie
              {
                  Title = (string)entry.Element(xa + "title"),
                  Url = (string)properties.Element(xd + "Url"),
                  BoxArtUrl = (string)properties.Element(xd + "BoxArt").Element(xd + "LargeUrl")
              };
          processMovies(movies.ToArray(), null);
      };
  
      try
      {
          client.DownloadStringAsync(new Uri(url));
      }
      catch (Exception ex)
      {
          processMovies(null, ex);
      }
  }

The sample leverages the WebClient asynchronous function versions.

One of the main differences between this sample and the prior sample is this sample wires up a lot of code and then sets the code in motion. Much of the control flow in the application has moved from the LoadMovies function to the execution status of the WebClient class.

Moving the code required some new exception handling. Sprinkled throughout the sample are cancellation checks after the asynchronous invocations.

Core application execution happens in code defined in LoadMoviesAsync and executed inside of QueryMoviesAsync. So, it's difficult to understand where the execution of the movie search actually begins and ends. A developer must read all the code to understand where it starts and ends. Contrast this with the synchronous example that starts at the top and drops out of the bottom.

The third example attempts to strike a happy medium and give a developer the performance of asynchronous, but the readability of synchronous.



Awaiting Future C# Asynchronous Features Brought to you by .NET Parallel Computing

Async with Await Statement

The sample code leveraging the Await statement appears below.

  async void LoadMoviesAsync(int year)
  {
      resultsPanel.Children.Clear();
      cts = new CancellationTokenSource();
      statusText.Text = "";
      var pageSize = 10;
      var imageCount = 0;
      try
      {
          while (true)
          {
              statusText.Text = string.Format("Searching...  {0} Titles", imageCount);
              var movies = await QueryMoviesAsync(year, imageCount, pageSize, cts.Token);
              if (movies.Length == 0) break;
              DisplayMovies(movies);
              imageCount += movies.Length;
          }
          statusText.Text = string.Format("{0} Titles", imageCount);
      }
      catch (TaskCanceledException)
      {
      }
      cts = null;
  
  }
  
  async Task<Movie[]> QueryMoviesAsync(int year, int first, int count, CancellationToken ct)
  {
      var client = new WebClient();
      var url = String.Format(query, year, first, count);
      var data = await client.DownloadStringTaskAsync(new Uri(url), ct);
      var movies =
          from entry in XDocument.Parse(data).Descendants(xa + "entry")
          let properties = entry.Element(xm + "properties")
          select new Movie
          {
              Title = (string)entry.Element(xa + "title"),
              Url = (string)properties.Element(xd + "Url"),
              BoxArtUrl = (string)properties.Element(xd + "BoxArt").Element(xd + "LargeUrl")
          };
      return movies.ToArray();
  }

At first glance the code looks a lot like the synchronous example. Closer inspection reveals three new components absent in the prior two samples:

  1. An "Async" keyword tagged to the functions.
  2. The Await keyword
  3. New Extension Functions for the WebClient class

According to the documentation "Async" is needed to signal the compiler that an "Await" statement will be used in the function. "Await" is really where all the action happens, but before looking at Await some discussion of the Task class is in order.

A complete introduction to the Task class is beyond the scope of this article, but you'll find helpful material here in my repvious article, Understanding Tasks in .NET Framework 4.0 Task Parallel Library.

To summarize, think of a Task as a wrapper for a piece of work (delegate). Tasks can be sent to a "Scheduler" for execution and can be aborted during execution. Tasks can return values, accept parameters, and return exceptions. Tasks can be joined to other Tasks, so the completion of one Task can start another Task (Continuation).

Await leverages the attributes of the Task class. I'll walk through what "Await" is doing using the QueryMoviesAsync function as an example. QueryMovieAsync function returns a Task<movie[]> class as soon as the function encounters the Await statement. In the "Async with delegates" sample, some other code does similar work, however the work had to be arranged according to the patterns in the WebClient class. In the Async sample, the complier does the arranging for you. So, when the Task completes the remaining part of the function executes.

New Extension Functions have been added to existing .NET Framework classes to take advantage of the "Await" statement's capabilities. These new functions return Task<t> classes instead of the usual Type.

Most important to notice is; though the code has synchronous readability having to deal with Task classes gives it a more asynchronous feel. There are special characteristics of asynchronous code that simply should not be hidden from a developer. So, the "Async" emphasis is more on making the code easier to structure.

Conclusion

"Await" is a new keyword in an upcoming version of C# programming. The new "Await" keyword leverages features of the Task class from the .NET Framework 4.0. Coupled with a new set of Extension Functions on existing .NET classes; the "Await" keyword results in a more approachable asynchronous development experience.

Related Articles





About the Author

Jeffrey Juday

Jeff is a software developer specializing in enterprise application integration solutions utilizing BizTalk, SharePoint, WCF, WF, and SQL Server. Jeff has been developing software with Microsoft tools for more than 15 years in a variety of industries including: military, manufacturing, financial services, management consulting, and computer security. Jeff is a Microsoft BizTalk MVP. Jeff spends his spare time with his wife Sherrill and daughter Alexandra.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • New IT trends to support worker mobility — such as VDI and BYOD — are quickly gaining interest and adoption. But just as with any new trend, there are concerns and pitfalls to avoid.  Download this paper to learn the most important considerations to keep in mind for your VDI project.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds