Best way to convert callback-based async method to awaitable task

C#AsynchronousTask Parallel-LibraryC# 5.0

C# Problem Overview


What would be the best way to convert/wrap a "classic" asynchronous method that uses a callback to something that returns a (awaitable) Task?

For example, given the following method:

public void GetStringFromUrl(string url, Action<string> onCompleted);

The only way I know of to wrap this into a method returning a task is:

public Task<string> GetStringFromUrl(string url)
{
     var t = new TaskCompletionSource<string>();

     GetStringFromUrl(url, s => t.TrySetResult(s));

     return t.Task;
}

Is this the only way to accomplish this?

And is there a way to wrap the call to GetStringFromUrl(url,callback) in the task itself (i.e. the call itself would run inside the task instead of synchronously)

C# Solutions


Solution 1 - C#

Your code is short, readable and efficient, so I don't understand why are you looking for alternatives, but I can't think of anything. I think your approach is reasonable.

I'm also not sure why do you think that the synchronous part is okay in the original version, but you want to avoid it in the Task-based one. If you think the synchronous part might take too long, fix it for both versions of the method.

But if you want to run it asynchronously (i.e. on the ThreadPool) only in the Task version, you can use Task.Run():

public Task<string> GetStringFromUrl(string url)
{
    return Task.Run(() =>
    {
        var t = new TaskCompletionSource<string>();

        GetStringFromUrl(url, s => t.TrySetResult(s));

        return t.Task;
    });
}

Solution 2 - C#

Your assumed implementation is perfectly fine for this assuming the callback only ever handles successful situations. What currently happens if an exception happens within the async underpinnings of the GetStringFromUrl implementation? There's no real way for them to propagate that to the Action callback... do they just swallow it and return you null or something?

The only thing I would recommend is using following the new convention of naming such async methods with the XXXAsync suffix.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPhilippe LeybaertView Question on Stackoverflow
Solution 1 - C#svickView Answer on Stackoverflow
Solution 2 - C#Drew MarshView Answer on Stackoverflow