Tuesday, May 22, 2012

Async VII: WinRT class library

In the previous post I talked about async from JavaScript. Now, for this I had to make a WinRT class library for my asynchronous RestCaller class, so this functionality could be used from a HTML5 JavaScript WinRT application. Now, once you do this, there are some things you need to know and some restrictions on the types you use for your publicly visible methods.

First of all you need to create a class library. Pretty simple, but once it's created, you need to change its' project type to WinMD file. This stands for Windows MetaData file.


Also, in the first version, my class library was called BlitzHiker.Lib. This name gave me runtime errors when called from JavaScript. At compile time everything was fine, but at runtime it would just crash for no reason. Removing the point from its' name fixed this.

Once I had the class library ready, I copied my RestCaller class to it and started compiling. The errors this gave were quite abundant. For starters, you are not allowed to use a return type of Task or Task<T> in a WinMD file. This forced me to define all of my existing methods as private. Which made it all compile just fine. But then again, you're nothing with private methods, you need some public ones as well.

private async Task PublishHikeRequestTaskAsync(CancellationToken token)
{
    var hikeRequest = GetHikeRequest();

    try
    {
        var client = new HttpClient();

        var url = string.Format("{0}/HikeRequest", BASE_URL);
        var response = await client.PostAsync(url, await BuildJsonContent(hikeRequest), token);
        response.EnsureSuccessStatusCode();
    }
    catch (HttpRequestException exc)
    {
        var dialog = new MessageDialog(exc.Message);
        dialog.ShowAsync();
    }
}

For each of these private methods I needed to define a public wrapper. The return types you are allowed to use on them are AsyncAction (as a replacement for Task) and AsyncOperation<T> (as a replacement for Task<T>).

The original method gets called by using AsyncInfo.Run (this changed in the recent CTP, the original type used was AsyncInfoFactory, but that one's gone. If you watch the Build sessions on async, you'll see them use the AsyncInfoFactory, but that just won't work anymore).

public IAsyncAction PublishHikeRequestAsync()
{
    return (IAsyncAction)AsyncInfo.Run((ct) => PublishHikeRequestTaskAsync(ct));
}

You can also see me sending along a CancellationToken. Since it's not passed along to the PublishHikeRequestAsync method, you will have to use a different way of cancelling than I showed in one of the previous posts.

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    cts = new CancellationTokenSource();

    try
    {
        await _restCaller.PublishHikeRequestAsync().AsTask(cts.Token);

        var driverIds = await _restCaller.GetDriversAsync().AsTask(cts.Token);

        if (driverIds != null)
            await ShowDriversOnMap(driverIds, cts.Token,
                new Progress<int>(p => statusText.Text = string.Format("{0} of {1}", p, driverIds.Count)));
    }
    catch (OperationCanceledException exc)
    {
        statusText.Text = exc.Message;
    }
}

Since you get an AsyncAction, and not a Task, you can call AsTask on this. With AsTask, you can send along your CancellationToken. This shows that before you all start using WinMD class libraries, just keep in mind that you are working with different types and that the usage will be different (more verbose) as well.

As for the AsyncOperation, that's pretty much the same as AsyncAction.

public IAsyncOperation<UserModel> GetUserAsync(Guid userId)
{
    return (IAsyncOperation<UserModel>)AsyncInfo.Run((ct) => GetUserTaskAsync(userId, ct));
}

And that's it. I hope you found these posts on async useful. Just keep in mind that all info given here is still based on a preview version of this library and things can still change a bit in the eventual release.

There are some drawbacks on using async. As with a lot in the .NET Framework, they make things really simple for you. The danger is that it's easy to forget what you are actually doing, defining callbacks. Just keep that in mind and you'll be fine.

No comments:

Post a Comment