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 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 Class

.NET Framework 4

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

#region using

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

#endregion

namespace Sharper
{
    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 is a nice class to know about!

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