Reputation: 843
I'm trying to find the best way to make my API async with multiple dependent calls
<top routes...>
public async Task<IHttpActionResult> Post()
{
/*... some sync items*/
int userId= await _ef.saveUser();
var siteInfo = callsite(userId);
return await _ef.updateUserLastModified(); //need to wait for other 2
}
So all 3 need to go in order, can I make a private function that runs that as a task? Are there any advantages to make it async? I basically just want it to thread those 3 calls.
Upvotes: 2
Views: 2882
Reputation: 53710
What you have is fine! Assuming the last line depends on the first two, your code is the correct way to await asynchronous calls and also execute synchronous code:
public async Task<IHttpActionResult> Post()
{
int userId = await _ef.saveUser(); // 1
var siteInfo = callsite(userId); // 2
return await _ef.updateUserLastModified(); // 3
}
Line 2 will not execute until line 1 is complete, and then line 3 will be awaited and return. Any synchronous code before the end of the method will also be executed "normally".
Async isn't the same thing as multithreading - it's just a way of telling the compiler that you need to wait for some asynchronous thing to finish before continuing.
Upvotes: 4
Reputation: 24545
The beauty of async
and await
is that you can write your code such that it reads like synchronous code. Let's break down what you have, as it is the correct implementation of asynchronous programming.
public async Task<IHttpActionResult> Post()
{
int userId = await _ef.saveUser();
var siteInfo = callsite(userId);
return await _ef.updateUserLastModified();
}
Method Signature
We define our publically accessible async
method, that happily returns a Task<IHttpActionResult>
and is named Post
, great.
Body Line 1
We then are declaring and assigning a variable named userId
the awaited result of the _ed.saveUser()
invocation. This means that saveUser
must return an Task<int>
, otherwise this wouldn't compile. The await
keyword is possible in this method block since we have used the async
keyword in the method signature. When we await
the saveUser
call the internal async state-machine captures a return location and then immediately returns control to the calling thread -- allowing it to do work elsewhere. After some unknown amount of time, and when the saving of the user is complete control is then resuming where it left off (potentially on the same thread or even on a thread pool thread) and the userId
variable is assigned.
Body Line 2
Once we have our userId
then and only then do we continue to the next line. If we mistakenly omitted the await
on the previous line and errantly declared our userId
variable as a var
instead of an int
, it would have been problematic as the variable would have been a Task<int>
rather than the materialized int
we desired. Notice, this is synchronous code -- which is perfectly fine and acceptable and in fact encouraged. Not every piece of logic needs to be async
, and the phrase "async all the way" actually means something else. It means, for example that instead of our Post
method being void
and calling .Result
on saveUser
you instead go async all the way.
Body Line 3
Finally, we are returning the awaited result of the _ef.udateUserLastModified()
method. We know that this too returns a Task<IHttpActionResult>
.
Upvotes: 2