TPL: Composing tasks

time to read 3 min | 417 words

What happens when you want to compose two distinct async operations into a single Task?

For example, let us imagine that we want to have a method that looks like this:

public void ConnectToServer()
{
    var connection = ServerConnection.CreateServerConnection(); // tcp connect
    connection.HandShakeWithServer(); // application level handshake
}

Now, we want to make this method async, using TPL. We can do this by changing the methods to return Task, so the API we have now is:

Task<ServerConnection> CreateServerConnectionAsync();
Task HandShakeWithServerAsync(); // instance method on ServerConnection

And we can now write the code like this:

public Task ConnectToServerAsync()
{
   return ServerConnection.CreateServerConnectionAsymc()
                 .ContinueWith(task => task.Result.HandShakeWithServerAsync());
}

There is just one problem with this approach, the task that we are returning is the first task, because the second task cannot be called as a chained ContinueWith.

We are actually returning a Task<Task>, so we can use task.Result.Result to wait for the final operation, but that seems like a very awkward API.

The challenge is figuring a way to compose those two operations in a way that expose only a single task.