Recently I've found a
question about real life scenarios for using rather unknown
TaskCompletionSource<T> class. I started thinking where I would use it and very quickly I found a good practical example.
I have a pet project LanguageTrainer that helps me in learning words in foreign languages. Some time ago I added Dropbox support to it. It allows me to export/import list of words to/from Dropbox. I developed it in synchronous way. Now I prefer an asynchronous approach and I want to take advantages of
async/await keywords.
The problem is that
DropNet library, that makes communication with Dropbox easy, doesn't use
async/await. It has asynchronous API but it is callback based. The really easy solution here is to use TaskCompletionSource<T>. Here is an example (simplified). Let's start with the original code that downloads a given file from Dropbox.
public void ProcessFile(string key, string secret, string path)
{
var client = new DropNetClient(key, secret);
// ...
var bytes = client.GetFile(path)
//Process bytes
}
The version that uses DropNet asynchronous API looks in the following way:
public void ProcessFileAsync(string key, string secret, string path)
{
var client = new DropNetClient(key, secret);
//...
client.GetFileAsync(path,
response =>
{
var bytes = response.RawBytes;
//Process bytes
},
ex =>
{
//Handle exception
});
}
And finally the asynchronous version with
async/await looks in the following way:
public async Task<Stream> ProcessFileAsync(string key, string secret, string path)
{
var client = new DropNetClient(key, secret);
//...
var tcs = new TaskCompletionSource<Stream>();
client.GetFileAsync(path, response => tcs.SetResult(new MemoryStream(response.RawBytes)), tcs.SetException);
return tcs.Task;
}
...
var bytes = await ProcessFileAsync(key, secret, path);
//Process bytes
The method
ProcessFileAsync is marked as
async and returns a task so it can be awaited. Easy. isn't it? A few lines of code and you can use
async/await with other types of asynchronous APIs.