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.