Chaining async methods

Viewed 8532

I'm attempting to chain together a few async methods I've created and I believe there is some fundamental misunderstanding on my part about how this works

Here's a representation of my code:

public async Task<bool> LoadFoo()
{
    return await Foo.ReadAsync("bar").ContinueWith((bar) =>
    {
        Foo.ReadAsync("baz").ContinueWith((baz) =>
        {
            Foo.ReadAsync("qux").ContinueWith((qux) =>
            {
                return true;
            });

            return true;
        });

        return true;
    });
}

public void LoadEverything()
{
    LoadFoo().ContinueWith((blah) =>
    {
        OtherLoadMethod();
    });
}

Now I was expecting when LoadEverything() was called that all of the ReadAsync methods in LoadFoo ("bar", "baz" and "qux") would run and complete, and after they all completed then the .ContinueWith in LoadEverything would run so that OtherLoadMethod() wouldn't execute until the "bar", "baz" and "qux" ReadAsync methods finished.

What I am actually seeing is that LoadFoo gets called and then OtherLoadMethod starts to run before getting to the final completion in LoadFoo (the ContinueWith of the "qux" ReadAsync).

Can someone help clear up my misunderstanding here? Why wouldn't the execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?

3 Answers

You can also use Unwrap:

public async Task<bool> LoadFoo()
{
    await Foo.ReadAsync("bar")
        .ContinueWith(_ => Foo.ReadAsync("baz")).Unwrap()
        .ContinueWith(_ => Foo.ReadAsync("qux")).Unwrap();
    return true;
}

public async Task LoadEverything()
{
    await LoadFoo().ContinueWith(_ => OtherLoadMethod()).Unwrap();
}

Did not expect the top solution in search engine was fixing a misunderstanding but not actually the solution of the topic itself.

Chaining call can make great context focus when developing, async is good, and it is better if you know what u r doing.

Code:

    //thanks for TheodorZoulias's review and input
public static class TaskHelper
{
    public static async Task<TOutput> ThenAsync<TInput, TOutput>(
        this Task<TInput> inputTask,
        Func<TInput, Task<TOutput>> continuationFunction,
        bool continueOnCapturedContext= true)
    {
        var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
        var output = await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
        return output;
    }
    public static async Task<TOutput> ThenAsync<TInput, TOutput>(
        this Task<TInput> inputTask,
        Func<TInput, TOutput> continuationFunction,
        bool continueOnCapturedContext= true)
    {
        var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
        var output = continuationFunction(input);
        return output;

    }

    public static async Task<TInput> ThenAsync<TInput>(
        this Task<TInput> inputTask,
        Action<TInput> continuationFunction,
        bool continueOnCapturedContext= true)
    {
        var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
        continuationFunction(input);
        return input;
    }

    public static async Task<TInput> ThenAsync<TInput>(
        this Task<TInput> inputTask,
        Func<TInput, Task> continuationFunction,
        bool continueOnCapturedContext= true)
    {
        var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
        await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
        return input;
    }




    public static async Task<TOutput> ThenAsync<TOutput>(
       this Task inputTask,
       Func<Task<TOutput>> continuationFunction,
       bool continueOnCapturedContext= true)
    {
        await inputTask.ConfigureAwait(continueOnCapturedContext);
        var output = await continuationFunction().ConfigureAwait(continueOnCapturedContext);
        return output;
    }

    public static async Task ThenAsync(
        this Task inputTask,
        Action continuationFunction,
        bool continueOnCapturedContext= true)
    {
        await inputTask.ConfigureAwait(continueOnCapturedContext);
        continuationFunction();
    }
}
Related