I created a simple WebApi project with a single controller and a single method:
public static class DoIt
{
public static async Task<string> GetStrAsync(Uri uri)
{
using (var client = new HttpClient())
{
var str = await client.GetStringAsync(uri);
return str;
}
}
}
public class TaskRunResultController : ApiController
{
public string Get()
{
var task = Task.Run(() =>
DoIt.GetStrAsync(new Uri("http://google.com"))
);
var result = task.Result;
return result;
}
}
I have a good understanding of async/await and tasks; almost religiously following Stephen Cleary. Just the existence of .Result
makes me anxious, and I expect this to deadlock. I understand that the Task.Run(...)
is wasteful, causing a thread to be occupied while waiting for the async DoIt()
to finish.
The problem is this is not deadlocking, and it's giving me heart palpitations.
I see some answers like https://mcmap.net/q/931163/-calling-an-async-method-using-a-task-run-seems-wrong, and I've also observed that SynchronizationContext.Current
is null when the lambda is executing. However, there are similar questions to mine asking why the above code does deadlock, and I've seen deadlocks occur in cases where ConfigureAwait(false)
is used (not capturing the context) in conjunction with .Result
.
What gives?