Palmier sur la plage de la grande anse, Le Diamant, Martinique

Extending existing .NET API to support asynchronous operations

Jan 5, 2012

Palmier sur la plage de la grande anse, Le Diamant, Martinique

The other day I needed a way in a project I am working on to turn a .NET API, RestSharp to name it, so that I could use it in an asynchronous way.

The goal was to have the API returning a Task<TResult> so that I could use it if I want with the Async CTP. I also wanted to have something running both on .NET 4.0 and on Windows Phone 7.5.

To achieve this goal I used

TaskCompletionSource?lt;TResult> Class

.NET Framework 4

and defined two helper extension methods on the RestClient class of RestSharp as this:

using System;
using System.Threading;
using System.Threading.Tasks;
using RestSharp;

public static class RestClientExtensions
{
    public static Task<TResult> ExecuteTask<TResult>(this RestClient client,
                                                     RestRequest request) where TResult : new()
    {
        var tcs = new TaskCompletionSource<TResult>();

        WaitCallback
            asyncWork = _ =>
                            {
                                try
                                {
                                    client.ExecuteAsync<TResult>(request,
                                                                 response => tcs.SetResult(response.Data));
                                }
                                catch (Exception exc)
                                {
                                    tcs.SetException(exc);
                                }
                            };

        return ExecuteTask(asyncWork, tcs);
    }

    public static Task<TResult> ExecuteTask<T, TResult>(this RestClient client,
                                                        RestRequest request,
                                                        Func<T, TResult> adapter) where T : new()
    {
        var tcs = new TaskCompletionSource<TResult>();

        WaitCallback
            asyncWork = _ =>
                            {
                                try
                                {
                                    client.ExecuteAsync<T>(request,
                                                           response =>
                                                           tcs.SetResult(adapter.Invoke(response.Data)));
                                }
                                catch (Exception exc)
                                {
                                    tcs.SetException(exc);
                                }
                            };

        return ExecuteTask(asyncWork, tcs);
    }

    private static Task<TResult> ExecuteTask<TResult>(WaitCallback asyncWork, TaskCompletionSource<TResult> tcs)
    {
        ThreadPool.QueueUserWorkItem(asyncWork);

        return tcs.Task;
    }
}

Now I can write asynchronous code like this:

public Task<List<Project>> GetAllProjects()
{
    var request = new RestRequest { Resource = "/httpAuth/app/rest/projects", RootElement = "project" };
    request.AddHeader("Accept", "application/json");

    return _restClient.ExecuteTask<List<Project>>(request);
}

So TaskCompletionSource<T> is a nice class to know about!

You might also watch this short video by Phil Pennington to get a better idea about it: