Click here to Skip to main content
Click here to Skip to main content

Working with IAsync* WinRT Methods

, 19 Jun 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
A chapter excerpt from Windows XAML in Action
Windows XAML in Action
By Pete Brown

Metro style applications built on the Windows Runtime are especially sensitive to any delays in the UI thread. Users will immediately notice when the UI trails their touch input and “doesn’t stick to their finger.” Animations that stutter and skip are immediately visible. Any lag in processing negatively affects the experience and the perception of not only your application, but the platform as a whole. A good way to help ensure your application doesn’t get into this state is to make long-running calls asynchronous. In this article, based on chapter 3 of Windows 8 XAML in Action, author Pete Brown discusses the Windows Runtime approach to asynchronous code.

You may also be interested in…

The Windows Runtime was built with the concept of asynchronous operations. It was also built with the idea that these asynchronous operations must work not only for C#, but also for JavaScript, C++, and any number of other, very different languages. For those reasons, the team didn’t take a dependency on the Task Parallel Library in .NET, but, instead, created an interface-based approach consistent with the rest of the Windows Runtime.

The Windows.Foundation namespace contains the types and interfaces required to support asynchronous functions in WinRT. Every asynchronous operation implements, at a minimum, the IAsyncInfo interface. Like most programming problems, there is an easy but limited way to do async and a more complex but capable way.

In this article, we’ll look at the different approaches for using the WinRT asynchronous APIs; that is, the ones which return IAsync* interfaces. I’ll cover the easiest approach and then look into what’s needed to check progress or cancel an asynchronous operation.

Async and Await: The Simplest Approach

The simplest and most commonly used approach is to use the await keyword. To use an awaitable function, it must be used in a function marked as async, and then all you need to do is use this keyword and call it like any normal synchronous function, as shown in listing 1.

Listing 1 Using the Await Keyword to Perform a Network Operation

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  LoadFeedUsingAwait(); #A
}

private async void LoadFeedUsingAwait() #B
{
  var client = new SyndicationClient();

  var uri = new Uri("http://feeds.feedburner.com/PeteBrown");
  var feed = await client.RetrieveFeedAsync(uri);  #C

  Debug.WriteLine(feed.Title.Text);
}
#A Function calls will go here
#B Method marked as async
#C Async call using await

The code in listing 1 goes in the code-behind for the main page on a new application. Note how the function is called from OnNavigatedTo. Run the application and (on a single display system) switch back to your IDE and look at the output window. You should see the title of my blog displayed there. On a dual display system, the Metro style app will show up on one display and the IDE on the other, so no switching is required.

Tip

Everyone knows that if it’s printed, it immediately has capital-A Authority, so here’s my little gift to you. Copy this paragraph and send it to your manager:

Dear developer bosses of the world: Metro style development on x86/x64 hardware needs developer machines with at least two displays to be effective. A second display is incredibly inexpensive, even if you purchase one of those snazzy 3M multi-touch displays. Without the second display, your developers will waste precious hours just in context switching between Metro and the desktop during debugging sessions. You’ll save time, money, and headaches by properly equipping your entire team.

Marking your methods with the async modifier causes the compiler to reconstruct the method, inserting possible suspend and resume points every place where you use the await operator. The compiler ensures all the state management is handled for you, so you don’t need to really think about the fact that your method may have stopped running. In order to use the await operator, the method must be marked as async.

Using the await operator makes it really easy to support making asynchronous calls—all the magic required to support asynchronous operations is wrapped up in code you never see. This approach works well for the majority of situations. However, when you want to check the progress of an operation or cancel an operation in-progress, you must use a slightly more complex approach.

Async and Await Under the Covers

When you use async and await in your code, the compiler does a lot on your behalf. Any function which is marked using the async modifier is rewritten as a state machine. All local function state is stored in a structure.

The code that implements the actual functionality you wrote is also located in a method named MoveNext on that same structure. Local variables become fields in the structure. Your original function ends up being just a bit of a shell which initializes the state machine and then passes control to it.

The implementation code starts with a switch statement which uses the current state as input. Depending upon that state variable, the code branches to one of the asynchronous calls, a check to see if the calls have completed and code to get the results, or the end of the function.

This state machine enables the function to be suspended and the state boxed on to the heap for reactivation once the asynchronous call returns.

Each completed step modifies the state. Each time the function is called, the opening switch statement branches the code so it picks up where it previously left off.

The end result is a lot of compiled code created on your behalf. If you’re curious about the inner workings of the asynchronous state machine, you can see the generated MSIL (Microsoft Intermediate Language) and more in my blog post on this topic: http://bit.ly/asyncstatemachine

Long-Form Asynchronous Operations

The async and await keywords are conveniences, but aren’t required when working with asynchronous operations. You can still use the long-form approach with event handlers and callback functions.

The options available to you depend upon which interfaces the return type of the asynchronous function implements. Table 1 shows the different interfaces and describes their capabilities.

Interface Description
IAsyncAction The most basic async support interface. This defines an asynchronous method which does not have a return type.
IAsyncActionWithProgress<TProgress> An interface which supports progress reporting of a supplied type.
IAsyncOperation<TResult> Interface which supports an asynchronous method which has a return value.
IAsyncOperationWithProgress<TResult,TProgress> Interface which supports an asynchronous method with both a return value, and progress reporting.
Table 1 Async support interfaces in WinRT. All asynchronous operations must return a type implementing at least one of these interfaces.

In addition, the IAsyncInfo interface supports the asynchronous operations by providing Cancel and Close methods, as well as get error and status information. The four interfaces include this capability as they inherit from IAsyncInfo.

You can also use the long form approach to make the call. In this case, the return type implements the most feature rich of the interfaces: IAsyncOperationWithProgress. That means when working with the SyndicationClient, we can get back both a result, but also get updates as the operation progresses. This is the signature:

public IAsyncOperationWithProgress<SyndicationFeed,RetrievalProgress>

                  RetrieveFeedAsync(System.Uri uri)

SyndicationFeed is the real return type—it’s the data you want. If this function were implemented without asynchronous operation in mind, it might look like this:

public SyndicationFeed RetrieveFeedAsync(System.Uri uri)

But it’s asynchronous, so the return type is a class implementing the interface. Listing 2 shows how to call the function using the long form asynchronous pattern. Call this function from OnNavigatedTo just as we did in listing 1.

Listing 2 Downloading a Syndication Feed Using the Long Form Approach

private void LoadFeedUsingLongForm()
{
  var client = new SyndicationClient();
 
  var uri = new Uri("http://feeds.feedburner.com/PeteBrown");
  var op = client.RetrieveFeedAsync(uri);
 
  op.Completed = (info, status) => #A
    {
      switch (status)
      {
        case AsyncStatus.Canceled: #B
          Debug.WriteLine("Operation was canceled");
          break;
        case AsyncStatus.Completed: #C
          Debug.WriteLine("Operation was completed");
          Debug.WriteLine(info.GetResults().Title.Text);
          break;
        case AsyncStatus.Error: #D
          Debug.WriteLine("Operation had an error:");
          Debug.WriteLine(info.ErrorCode.Message);
          break;
      }
    };
}
#A Completed delegate
#B Operation canceled
#C Operation complete
#D Operation error

Notice how Completed is not an event handler. Instead, it is simply a delegate property. For that reason, you use = rather than += when adding your handler code. This subtle difference could trip you up if you don’t recognize it right off the bat.

When you run this, the Completed delegate will be called, which will then write out the title of my blog in the debug window in the IDE. As before, you’ll need to terminate the application from the IDE.

What about race conditions?

If you look at the code in listing 2, you may wonder about a possible race condition between executing the function and wiring up the Completed handler.

In regular .NET asynchronous code following the event approach, you need to wire up the event handlers before executing the operation. This is to ensure that the event handlers are available before the function needs them. For potentially fast async operations, this is especially important.

In the Windows Runtime, however, the operation begins execution as soon as you call the function. There is no way for you to wire up a handler in between declaration and execution. Could there be a race condition there where the operation completes before the handler is available?

Luckily, the Windows Runtime team thought of this very situation, and ensured it will not happen. The returned operation contains everything that is needed for asynchronous function management. If the function call completes before you wire up the handler, the operation is still around and is able to manage context and handlers. In that scenario, as soon as you make the handler available, the operation will call it.

So, you don’t need to worry about race conditions with setting up your handlers. The team already did.

This same thought was put into Task for functions such as ContinueWith.

Knowing when the task is complete is essential. For some long-running tasks, you may want to get some information about interim status.

Getting Progress Updates

Some especially long tasks, such as downloading a large file over a slow connection or processing a large amount of data, should report back progress information to the calling code. This becomes especially important in the tablet market where bandwidth varies greatly from location to location.

To support flexible progress reporting, the IAsyncActionWithProgress and IAsyncOperationWithProgress interfaces provide a way for an asynchronous function to provide status updates using whatever data format is appropriate for that function.

In this case, the reporting type is a RetrievalProgress structure which exposes two properties: bytesRetrieved and totalBytesToRetrieve. Using these two properties, you can figure out the percentage complete and percentage left. Listing 3 shows how.

Listing 3 Obtaining Progress Reports from the RSS Feed Downloader

private void LoadFeedUsingLongForm()
{
  var client = new SyndicationClient();
 
  var uri = new Uri("http://feeds.feedburner.com/PeteBrown");
  var op = client.RetrieveFeedAsync(uri);
 
  op.Completed = (info, status) =>
    {
      ... #A
    };
 
  op.Progress = (info, progress) => #B
    {
      Debug.WriteLine(string.Format("{0}/{1} bytes {2:P}", 
        progress.bytesRetrieved, 
        progress.totalBytesToRetrieve,
        (float)progress.bytesRetrieved /  
               (float)progress.totalBytesToRetrieve));
    };
}
#A Code in previous listing
#B Progress report

This code is identical to listing 2, with the addition of a Progress handler. During execution, at a frequency determined by the code you’re calling, you’ll receive progress updates through this handler.

When I ran the above code, however, I got some pretty interesting results. The totalBytesToRetrieve was incorrect, reporting a meaningless number. If I changed the URI to http://10rem.net/blog/rss.aspx[1] instead, I got the correct results:

4096/205187 bytes 2.00 %
8192/205187 bytes 3.99 %
12288/205187 bytes 5.99 %
16384/205187 bytes 7.98 %
 [snip]
200704/205187 bytes 97.82 %
204800/205187 bytes 99.81 %
205187/205187 bytes 100.00 %
Operation was completed
Pete Brown's Blog (POKE 53280,0)

Not all services correctly report the total bytes. In this case, Feedburner clearly does not. When performing your own download, you’ll need to check that number and adjust your progress reporting appropriately. One way would be to show an indeterminate progress bar in the case of unreported total bytes.

What about long-running operations that you need to abort? How would you deal with that situation?

Cancelling the Operation

For especially long-running operations, such as downloading a file, you’ll want to provide a way for the user to cancel. When I’ve had to do this in the past, I would provide a "cancel" button, which would then set a flag. The code doing the long running operation, typically in a loop or timer, would check this flag during each iteration. If the cancel flag was set, the operation would terminate and clean up after itself.

When working with asynchronous code in the Windows Runtime, the process is not all that different from the approach I described. However, instead of setting a flag, you call the Cancel function on the operation. The executing code uses this to determine what steps to take.

Listing 4 is an update to listing 3, which will cancel after a set number of bytes have been downloaded. We haven’t yet covered controls and the UI, so I don’t want to deal with buttons and whatnot just yet.

Listing 4 Cancelling the Operation After 5,000 Bytes have been Downloaded

bool alreadyCancelled = false; #A
op.Progress = (info, progress) =>
  {
    Debug.WriteLine(string.Format("{0}/{1} bytes {2:P}",
        progress.bytesRetrieved,
        progress.totalBytesToRetrieve,
        (float)progress.bytesRetrieved /
              (float)progress.totalBytesToRetrieve));
 
    if (!alreadyCancelled) #A
    {
      if (progress.bytesRetrieved > 5000)
      {
        info.Cancel();        #B
        alreadyCancelled = true;
      }
    }
  };
#A Prevent redundant Cancel calls
#B Cancel operation

This listing shows one approach to cancelling. Typically, you’d use a button or other user interface device to call the Cancel method, as stated above.

One important thing to note from this listing is that, when you run it, you may not see it actually cancel until the operation is complete. Remember, this is an asynchronous operation, and the function is responsible for deciding when it can cancel, and how quickly to do so. For grins, if you change the 5000 to 0, you’ll likely see it cancel right away.

Looking at these various long-form approaches to asynchronous code may make you double-check to see if you accidentally hit 88 mph in a DeLorean while you were napping. It certainly may feel like we’ve gone backwards, but, with the addition of async and await now making this verbose approach optional, I can assure you that we’re going in the right direction.

If you want the flexibility and power, choose the long/verbose version. If you don’t need all that flexibility (which will likely be the majority of the time—do you really need progress reporting or cancellation when opening a file?), use the async and await keywords to make your life easier. Don’t force yourself or your team to pick just one approach; use what works for the specific situation and keep it as simple as possible as often as possible.

Summary

Over the past years, asynchronous operations have become a fact of life for developers. I blame Ajax[2] and JavaScript for it, but, then again, I generally blame those two for all the things I dislike. No, what’s really to blame here is the expectations of the user. There was a time when it was perfectly acceptable to have your application lock up and be unresponsive during a long calculation or other operation. Many applications would hang when doing something as simple as printing.

But then we started adding in animation, and not just the cute dancing baby type of animation made popular on GeoCities and Angelfire, but animation that is both useful and conveys information. Operations which caused the animation to stutter or skip suddenly became a real problem. For browsers, and browser plug-in technologies like Silverlight, and even desktop technologies like WPF, the recommended networking (the biggest latency issue by far) approach was to use asynchronous code. Browsers and Silverlight required it, WPF didn’t. The result was clear, if it wasn’t required, it didn’t happen.

Finally, the straw that broke the camel’s back was touch interaction. Touching a UI is such an immediate and deep interaction, that any sort of lag in responsiveness becomes immediately noticeable. When you put apps that rely on touch, on a tablet designed for touch, using a relatively low-power ARM processor, any and all lag becomes immediately noticeable. Importantly, users who see the lag don’t generally think "wow, that app stinks", but instead think "wow, this tablet stinks". So, Microsoft made the decision to make anything even remotely slow into an asynchronous API.

This was the right decision, and because of the addition of the async and await keywords, it also became a decision that is really easy to swallow. Unless you want to take on the added complexity because you need to report progress, or provide an option to cancel an operation, you can simply use the helpful keywords and forget all about the operation being asynchronous at all.

The Windows Runtime includes asynchronous methods all over. Additionally, the .NET libraries used for writing C# Metro style applications also include asynchronous code. However, those libraries use the Task class rather than the WinRT interface-based asynchronous approach. This helps keep .NET consistent with the desktop version, and also with the previous version of .NET. Gladly you can use async and await just as easily with a .NET Task as you can with a WinRT IAsync* interface. Plus, if you really want to keep your code consistent, you can easily convert between the two approaches using included extension methods.

Asynchronous code used to be something we dreaded in application development. With both Task and IAsync*, and the new async and await keywords, combined with the appropriate use of asynchronous operations throughout the libraries, I feel like, for the first time, we really have async done right. Async everywhere? I’m cool with that.

Here are some other Manning titles you might be interested in:

HTML5 for .NET Developers
Jim Jackson II and Ian Gilman

Learn Windows IIS in a Month of Lunches
Jason Helmick

Silverlight 5 in Action
Pete Brown

[1] My source RSS feed, which I use to feed the far more scalable and reliable Feedburner feed

[2] And you too, jQuery! I know what game you’re playing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Manning

United States United States
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 19 Jun 2012
Article Copyright 2012 by Manning
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid