Using the result of an asynchronous method

I have a simple async method with signature:

public async Task<bool> AllowAccessAsync(string authenticatedUserToken)

      

When calling this method, I have two parameters when assigning its result to a local variable:

bool response = null;
// option 1
await this.transportService.AllowAccessAsync(authenticatedUserToken).ContinueWith(task => response = task.Result);
// option 2
response = await this.transportService.AllowAccessAsync(authenticatedUserToken);

      

The former uses a continuation delegate to assign a local variable, the latter assigns the result directly to the variable.

Do they have the same result? Are there any benefits to either approach? Is there a better way to do this?

+3


source to share


4 answers


Do they have the same result?

Edit:

@Servy correctly points out that since it ContinueWith

is just a projection of the result. This means that both operations are semantically equivalent, but the exception is tricky that they will behave differently.

Are there any benefits to either approach? Is there a better way to do this?



Edit 2:

The following note applies to using async-await

vs ContinueWith

in general. If you look at both examples as they both use async-await

, definitely use the latter as both contain machine state generation, but the latter will propagate AggregateException

if an exception is thrown.

async-await

has minimal overhead when building a state machine, and ContinueWith

doesn't. On the other hand, using async-await

allows you to "feel" synchronously, effectively being asynchronous, and saves you verbosity ContinueWith

. I would definitely go with it async-await

, although I advise you to research the correct way to use it as it might be unexpectedly pathetic.

+6


source


Using async/await

with a parallel task library ContinueWith

you will mix patterns unnecessarily. There are a number of reasons not to do this if you have no choice, not least because the async/await

SynchronizationContext

default of ContinueWith is not saved .



So option 2 is correct.

+4


source


Do they have the same result?

Yes, both options will end up setting the same result inresponse

. The only difference occurs when there is an exception. In the first option, the Excluded Exception will be a wrapper AggregateException

around the actual exception, and in the second, the actual exception.

Are there any benefits to either approach?

There is absolutely no advantage to using it ContinueWith

this way
. The second option has the advantages of better exception handling and is much easier to write and read.

Is there a better way to do this?

Not exactly how you use async-await.


As Servy said, that doesn't mean it ContinueWith

should have been used. The equivalent ContinueWith

is to put the rest of the method in a continuation. So instead of this:

public async Task FooAsync()
{
    var response = await this.transportService.AllowAccessAsync(authenticatedUserToken);
    Console.WriteLine(response);
}

      

You would do this:

public Task FooAsync()
{
    return this.transportService.AllowAccessAsync(authenticatedUserToken).
        ContinueWith(task => Console.WriteLine(task.GetAwaiter().GetResult()));
}

      

It has some performance advantages as it doesn't need an async-wait machine, but it is very difficult to get right.

+4


source


It has more to do with coding style.

The first style can be useful when you have a large workflow that might require assigning different continuations to keep a promise. However, it relies on closures. I would not recommend this usage as it is not always predictable. ContinueWith

should be used when you create workflows and each step depends only on the previous ones and does not interact with the external scope, except for the task that produces the final result (which you expect next).

The second is useful when you are simply interested in the result.

It also ContinueWith

allows you to specify TaskScheduler

, since the one that comes by default with your application may not be the one you want.

More on TaskScheduler

here: http://blog.stephencleary.com/2015/01/a-tour-of-task-part-7-continuations.html

+2


source







All Articles