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: