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
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
You might also watch this short video by Phil Pennington to get a better idea about it: