Reputation: 26336
I want to use TPL with a existing API, RestSharp to be specific, so I can use continuations.
But this means I have to wrap a API that doesn't take the classical .NET approach to async, but instead implements callbacks. Take some code like this:
var client = new RestClient("service-url");
var request = new RestRequest();
client.ExecuteAsync<List<LiveTileWeatherResponse>>(request,
(response) =>
{
...
});
So here I want to wrap the ExecuteAsync in TPL, if it's possible. But I can't for the life of me, figure out how to do it.
Any ideas?
Upvotes: 8
Views: 1378
Reputation: 763
This was a major pain point for me when learning the TPL as well.
What you're looking for is TaskCompletionSource
. When you create a TaskCompletionSource
, it creates a special Task
object (accessible by the TaskCompletionSource.Task
property) which only completes when you call the SetResult
or SetException
methods on the associated TaskCompletionSource
.
This post explains how to wrap APM operations with the TPL (and also Rx). See also this gist demonstrating an APM operation wrapped in the TPL.
Upvotes: 1
Reputation: 7388
TPL provides TaskCompletionSource class which allows you to expose pretty much anything as a Task. By calling SetResult or SetException, you can cause the task to succeed or fail. In your example, you could probably do something like:
static Task<T> ExecuteTask<T>(this RestClient client, RestRequest request)
{
var tcs = new TaskCompletionSource<T>();
client.ExecuteAsync<T>(request, response => tcs.SetResult(response));
return tcs.Task;
}
You can then use it:
var task = client.ExecuteTask<List<LiveTileWeatherResponse>>(request);
foreach (var tile in task.Result)
{}
Or, if you want to chain tasks:
var task = client.ExecuteTask<List<LiveTileWeatherResponse>>(request);
task.ContinueWith(
t =>
{
foreach (var tile in t.Result)
{}
}
);
You can read more about TaskCompletionSource at http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx
Upvotes: 12