Technically, that works, but it works by creating a new thread to perform a synchronous operation, which itself is wrapping and blocking on an inherently asynchronous operation. That means you're not getting some of the biggest benefits of going async
in the first place.
The right way is to go asynchronous all the way. Whereas right now you probably have something like this:
private class UserService
{
public IdentityUser GetById(int id)
{
return mContext.Users.Single(u => u.Id == id);
}
}
... you should now create an async version:
private class UserService
{
public async Task<IdentityUser> GetByIdAsync(int id)
{
return await mContext.Users.SingleAsync(u => u.Id == id);
}
}
Usage:
public async Task<IdentityUser> GetByIdAsync(int id)
{
return await _userService.GetByIdAsync(id);
}
Supposing, of course, that your underlying framework supports asynchronous methods like SingleAsync()
for inherently asynchronous operations, this will allow the system to release the current thread while you wait for the database operation to complete. The thread can be reused elsewhere, and when the operation is done, you can use whatever thread happens to be available at that time.
It's probably also worth reading about and adopting these Best Practices. You'll probably want to use .ConfigureAwait(false)
anywhere that you're not accessing contextual information like sessions and requests, for example.
This answer assumes, of course, that GetById
is inherently asynchronous: you're retrieving it from a hard drive or network location or something. If it's calculating the user's ID using a long-running CPU operation, then Task.Run()
is a good way to go, and you'll probably want to additionally specify that it's a long-running task in the arguments to Task.Run()
.