Monday, April 30, 2012

Async I: The Basics

In the recent talk I gave for Visug, we looked at the new async capabilities in the next version of the .NET Framework. The slides of this session can be found here. In this series of posts, I would like to walk you through the different demo's I showed during this talk.

The demo's were actually a rewrite of an existing application, the Blitzhiker application, we've developed for Windows Phone. The rewrite is a port of this application to the Windows 8 runtime.

The Blitzhiker application itself tries to bring hikers (people looking for a ride) and drivers (people with a car) closer together.


Hikers can publish hikerequests and get an overview of drivers and other hikers nearby. Below you can see a screen shot after a hiker has published his request. A Bing map is shown with pushpins for each driver nearby. Since all calls are done asynchronously, the entire user interface stays responsive while pushpins are shown on the map.



First thing we will take a look at, is the basics of asynchronous calls. What makes up an asynchronous call and how does it affect the execution of your program.

The code to publish the hikerequest, show the drivers on the map and after that show the hikers on the map, looks like this:

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    await _restCaller.PublishHikeRequest();

    var driverIds = await _restCaller.GetDrivers();

    if (driverIds != null) 
        await ShowDriversOnMap(driverIds);

    var hikerIds = await _restCaller.GetHikers();

    if (hikerIds != null) 
        await ShowHikersOnMap(hikerIds);
}

What happens is that we publish a hikerequest, after that, ask for all of the drivers on our route, next, show these guys on our map, then, get all of the hikers near us and show these on the map as well. The ShowDriversOnMap is a call that usually takes some time when there are a lot of drivers nearby. What we notice though is, that while showing the drivers, the entire application stays responsive, which is actually what we want from asynchronous calls.

You can spot the use of several awaits in the OnNavigatedTo method. What happens is that an await kicks of the execution of an asynchronous method and turns the rest of your method body into a callback. So in this piece of code several callbacks will be created at compile time, without you needing to mess up your code for this, you can keep on writing as if you are writing synchronous code.

What is also interesting about awaiting code this way, is that each callback will be executed in the same execution context that kicked of the asynchronous call. So, if you were on a UI thread, your callback will be executed on the UI thread. No need for Dispatcher.Invoke!

You probably noticed as well the use of the async keyword. This tells the compiler that the current method contains asynchronous calls and that there will probably need to be some extra compiler effort to create the necessary callbacks. Once you use the await keyword in a method, you need to put the async keyword in the method header. If you don't, your code won't compile. An async method can either have a void return type (as is the case in our piece of code) or can have a Task or Task<T> return type. Let's take a look at the ShowDriversOnMap method, which has a Task return type.

private async Task ShowDriversOnMap(List&lt;Guid> driverIds)
{
    foreach (var driverId in driverIds)
    {
        var driver = await _restCaller.GetUser(driverId);
        var pushpin = new Pushpin();
        pushpin.Text = "D";
        pushpin.Tapped += async (s, args) =>
        {
            MessageDialog dialog = 
                new MessageDialog(string.Format("This is {0}.", driver.FullName));
            await dialog.ShowAsync();
            MessageDialog secondDialog = 
                new MessageDialog("I am shown only after the previous dialog finishes.");
            await secondDialog.ShowAsync();
        };

        MapLayer.SetPosition(pushpin, 
            new Location(driver.LatitudeFrom, driver.LongitudeFrom));
        MyMap.Children.Add(pushpin);
    }
}

Again the await keyword is used, kicking of an asynchronous method and automatically turning the rest of the method body into a callback. You can also spot the use of the await keyword inside of a lambda expression. In WinRT there is no more DialogBox, but a MessageDialog. This one doesn't have a Show method, but a ShowAsync method, so, again, you can use await on this. Once you do this, you need to mark the lambda expression with the async keyword as well. I actually show 2 MessageDialogs with an await keyword. If you would set breakpoints in this lambda, you would spot the first dialog being shown and your code not starting to create the second dialog until you close the first one. That's the callback kicking in.

That's it for the basics of asynchronous calls. In a next post, we will go into exception handling and take a look at the RestCaller class that is being used in the code examples of this blog post.

No comments:

Post a Comment