1

So I have a function that looks like:

    async Task DoSomething() {
        var result = await GetDataForAsyncCall2();
        if (result != null) {
            await AsyncCall2(result.result1, result.result2);
        }
    }

My problem is that whenever I try to call it, it seems to return from the function after the GetDataForAsyncCall2() is called. But the actual result I want from the function is AsyncCall2.

Why would my function be returning after the first await, or how can I ensure the second await is ran before the function returns?

gspeager
  • 25
  • 4
  • You are waiting on the second task, assuming result is not null – BradleyDotNET Jan 30 '17 at 23:21
  • 4
    That's how `await` works; it will come back to your function when the async call finishes. – SLaks Jan 30 '17 at 23:21
  • 1
    Are you invoking your method with `await`? For example: `await DoSomething();`? Or are you merely calling `DoSomething();` – Rob Jan 30 '17 at 23:24
  • if `result` is `null` after the first await then it will return from the method. debug your code and verify that a result is actually being returned from `GetDataForAsyncCall2` – Nkosi Jan 30 '17 at 23:36
  • You might want to look into the 'continue with' method. https://msdn.microsoft.com/en-us/library/dd991174(v=vs.110).aspx – Paul Jan 30 '17 at 23:38
  • You need to show invoking code too - see [MCVE] for guidance on posting code (as @SLaks commented this is likely expected behavior). Note that it would be good idea to actually return result you are interested in from the function rather than returning `void` (http://stackoverflow.com/questions/6045343/how-to-make-an-asynchronous-method-return-a-value) – Alexei Levenkov Jan 31 '17 at 00:16
  • Your `DoSomething()` method returns at the `await` statements (first and second), because that's what `async` methods do. They return control to the caller (which at the first `await` statement is your actual, original caller) until the asynchronous operation has completed, at which point the method resumes executing. You need to either `await` the call, or use some other mechanism to wait, asynchronously or synchronously. See marked duplicate for additional details. – Peter Duniho Jan 31 '17 at 03:49

1 Answers1

5

Why would my function be returning after the first await?

The fact that you are asking the question indicates that you must have some completely false beliefs about what await does. This is like asking why return returns. An await is a kind of return. (Just like yield return is a kind of return in an iterator block. yield return and await are at some level essentially the same thing; they are both points at which a workflow returns to its caller and signs up the remainder of the method to run in the future.)

You probably need to do some research as to what await actually means in C#. Briefly, await means "if the results of this task are not available then return to my caller so that it can keep working. Pick up at this point some time in the future after the task I'm waiting for is complete." That is, asynchronously wait for the task to complete.

If this is the first await you hit in the method then the thing returned to the caller will be a task representing the method itself, because now it is not complete either, and the caller probably wants to await it.

But that brief explanation is likely not enough. You should read some articles or tutorials on how this works so that you can use it more effectively.

how can I ensure the second await is ran before the function returns?

You don't. That's by design. Awaits allow you to identify the points in an asynchronous workflow that are (1) high latency operations, and (2) where the operation must be completed before the remainder of the workflow executes. The sequence of awaits you have correctly represents the data dependency of the second high-latency task on the first. The system is working as designed.

But the actual result I want from the function is AsyncCall2.

I assume that the "result" you are after is a side effect since no value is extracted from AsyncCall2, and you have a valueless task returned from the method.

That's precisely what you get. Your method returns a task and that task will be marked as completed at some point in the future after the task returned by AsyncCall2 is completed. If your caller wants to asynchronously wait for that time in the future then it should await the returned task.

Again: an await is a point in an asynchronous workflow where we know that before it, the task has likely not completed, and after it, it definitely has completed.

A question that you did not ask:

Should I solve my problem by synchronously waiting for the high latency operation using .Result or similar?

No. That not only defeats the entire purpose of using await to manage latency. It also can cause you to wait forever. See http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html for some examples.

These examples are highly educational; I would read them very carefully until you thoroughly understand how await works.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067