Quantcast
Viewing all articles
Browse latest Browse all 16

Async extension method wrappers

Asynchronous APIs are becoming more popular thanks in part to the focus on asynchronous user interface design requirements on platforms such as Windows Store Applications for Windows 8 and Windows RT.

This attempt to change the way developers think about long or unpredictable operations is welcome and necessary as databases and files slowly migrate into the cloud.

Unfortunately System.Threading.Tasks and the async and await keywords are not available inside portable class libraries or some of the platforms we target with the Ambidect technology.  We could choose to use an alternative style of asynchronous API, such as call backs, but these are starting to look dated, and require the developer to do a lot more boilerplate work to use.

At this point you may be tempted to give up and provide only an blocking synchronous API and require the developer to manage their own threads on each platform that insists on asynchronous calls; but as I touched on in my previous post about the repository API, we felt it was a much better idea to provide an async API and did so using extension methods.

This technique can be used to wrap almost any synchronous API; but I have to stress at this stage it should only be used if the platform or platforms you are working on do not have a usable native asynchronous API.

For our example we’ll work with the Find method of the IRepository<> interface, but the principles here will work with any synchronous call that needs to be wrapped.

The first thing we need to do is create class to host our extension methods:

using System;
using System.Threading.Tasks;

namespace Mvpc
{
    public static class IRepositoryExensions_Async
    {
        // TODO this is where to put your extension method code.
    }
}

If you are not familiar with extension methods, the reason we mark the class as static is because its a requirement of the extension method support of the compiler.  The name of the class can be anything you want, but you can see that I use a simple convention that makes it clear to anybody using the library that the class contains extension methods, so is of no interest to be used directly.

You will note that the class here has been put into the Mvpc namespace to go alongside the class we are wrapping.  When using extension methods that extend the API with asynchronous members this is my recommended approach.  It stops the developer of the class worrying about how the async methods are provided, and intilisense will include them in the list of available class members when working on a platform that supports our asynchronous API.

In cases where the extension methods provide utility functions rather than a core API for a class, it is good practice to keep your extension methods in a separate namespace, e.g. Mvpc.Extensions.  This stops the intilisense list being over-populated with extension methods that are not relevant to the code at hand.  When extending one of the CLRs core types such as object or string I always insist that the extension method goes into a namespace ending in “Extensions” such as Mvpc.Extensions that the developer has to explicitly opt into.  This not only helps keeps the intilisense clean, but also stops accidental dependencies on the specific extension methods creaping into code blocks where they don’t belong.

Now we have a class setup and have decided the right namespace for the class lets add an extension method.  An extension method is exactly the same as a normal static method, except its first parameter is prefixed with the “this” keyword.  This instruction tells the compiler that it can effectively rewrite the extension method call into a static method call, while allowing the developer using the extension method to use a more natural calling convention.  For example instead of having to call:

var repository = ...;
var key = Guid.NewGuid();
IRepositoryBaseExtensions_Async.FindAsync(repository, key);

We can use the much more readable:

var repository = ...;
var key = Guid.NewGuid();
repository.FindAsync(key);

Lets have a look at the code for the FindAsync() extension method itself now:

        public async static Task FindAsync(this IRepository repository, params Guid[] keys)
        {
            var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                var ret = repository.Find(keys);
                return ret;
            });

            return await task;
        }

The first thing you will note is that we suffix the name of the method with “Async” I find this a very good convention to follow for any method that provides an async API that can have “await” applied to it. It helps the person using the method remember that at some point they will likely want to await on the result.

If you are unfamiliar with the async and await keywords I suggest you have a look at them in the MSDN documentation sufficient to say here that you use async to mark a method as containing asynchronous code, and await to safely wait for the result of an async method before continuing.

As well as the async keyword you will notice the method is also marked as static as it will operate without a class instance and the first parameter is prefixed with “this” keyword to enable the extension method style shorthand call to the method.  We can still call the static method directly if we want, but without the “this” keyword the extension method syntax would not be available when calling the method.

Inside the method we create a new Task with the right return type and use an lambda expression to perform a call to the synchronous API we are wrapping.  This code will be executed in a separate thread before returning its result.  Exactly when the code pauses to wait for the result depends on how we use await when calling the extension method.

More often that not when we will want the code to wait for the value before continuing so we will use await directly on the async call as follows:

var repository = ...;
var key = Guid.NewGuid();
var item = await repository.FindAsync(key);

In this post we’ve wrapped a synchronous call to a repository function with an async extension method, but you can use the technique whenever you find you need to make regular asynchronous calls to a class that couldn’t be built with an asynchronous API, or to which you do not have access to the source to extend with a native asynchronous API yourself.


Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

Viewing all articles
Browse latest Browse all 16

Trending Articles