Converting Callback Functions to Task Pattern

I was recently working on a Windows Store (Metro) app.  I was given a proxy class to communicate with the server.  Proxy class was following the callback pattern.  What I mean by that is when I invoke a server side method, I pass in an Action<T> that would be invoked when the server call completes.

Personally I now like async / await pattern much more now.  It seems more readable and more predictable.  It also help me provide better structured error handling.  So, I decided to wrap proxy calls inside Task wrappers.  I would like to quickly document how to do this in this blog post.

First of all, let’s look at the proxy code method.

public string GetData(Action<ServerResult> callback);

What I would like to have is something like

public async Task<ServerResult> GetData();

To get from one to the other I will use TaskCompletionSource class.  It will help me quite a bit. Actually, here is the final version of the wrapper method.

public async Task<ServerResult> GetServerData()
{
    try
    {
        var proxy = new Proxy(new Uri("http://mysite.com/getdata"));
        var taskCompletionSource = new TaskCompletionSource<ServerResult>();
        var task = taskCompletionSource.Task;
        Action<ServerResult> callback = taskCompletionSource.SetResult;
        await Task.Factory.StartNew(() =>
        {
            try
            {
                proxy.GetData(callback);
            }
            catch (Exception exception)
            {
                taskCompletionSource.SetException(exception);
            }
        }, TaskCreationOptions.AttachedToParent);
        return await Task.FromResult(new ServerResult(task.Result.Result));
    }
    catch (Exception exception)
    {
        return new ServerResult(exception);
    }
}

Let’s walk through the code above.  I am creating new instance of my proxy class.  Then I am creating task completion source, which is a class that will monitor my results and set my task as completed as well as set the results of that task.  I am adding exception handling so that I can cleanly send exceptions to the calling code from both task and general exceptions.  Server result class with contain either real data or an exception.  Of course, in real app I would have two properties – one for exception, the other for results.

namespace WpfApplicationAsync
{
    public class ServerResult
    {
        public ServerResult(object result)
        {
            Result = result;
        }
        public object Result { get; private set; }
    }
}

To call GetServerData method I can do the following.

        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            MainTextbox.Text = "";
            var result = await GetServerData();
            Action action = () =>
                {
                    MainTextbox.Text = 
                        MainTextbox.Text + 
                        result.Result + 
                        Environment.NewLine;
                };
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, action);
            
        }

I am calling my method GetServerData from my button.  Since I am adding all error handling to GetServerData, I do not need to use try/catch.  Any exceptions are going to be contained within ServerResult class.

Here is my test code from Proxy class.

    public class Proxy
    {
        public Proxy(Uri uri)
        {
            Uri = uri;
        }

        public Uri Uri { get; private set; }

        public void GetData(Action<ServerResult> callbak)
        {
            Thread.Sleep(5000);
            callbak(new ServerResult("Done"));
        }
    }

Again, this blog is just illustrate an approach of converting callbacks to awaitable tasks.  I find the code from Button click that awaits the results much cleaner than passing callbacks around.

4 Comments

  1. Pingback: Rethreading a single threaded app. | Musings of an Augmented Reality Philosopher

  2. Pingback: Using async BCL with async function | Ziernicki Answers

  3. When using Task.Factory.StartNew you will create a new thread to wait for the callback. Normally the purpose of async/await pattern is to release a thread while waiting for a I/O response. It probably doesn’t matter in your case, but for others that want to convert from callback to async/await pattern in a code library they should avoid this solution.
    I suggest looking here instead:
    https://joebuschmann.com/taskcompletionsource-bridging-the-gap-between-old-and-new/
    https://blog.rsuter.com/create-task-based-method-from-legacy-callback-method/

Leave a Reply to Chris Bordeman Cancel reply

Your email address will not be published. Required fields are marked *