This question already has an answer here:
I was experimenting with an MSDN sample. I came across the following issue. When running an async
block of code from a button click event handler, with async
pattern, it works fine (button1_Click
). But for button2_Click
, the control is not going beyond TaskObj.Result
. What might be the reason for the same?
private async void button1_Click(object sender, EventArgs e)//this works fine
{
Task<int> TaskObj = AccessTheWebAsync();
string a ="I came here..";
int y = await TaskObj;
string a1 = "I came here also..";
}
private void button2_Click(object sender, EventArgs e)//this is not working
{
Task<int> TaskObj = AccessTheWebAsync();
string a = "I came here..";//control yielded here
int y = TaskObj.Result;//something happened here
string a1 = "Why I couldn't come here?";//why control is not reaching here?
}
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
private void DoIndependentWork()
{
IList<Int32>intK = Enumerable.Range(1, 100000000).ToList();
foreach (int x in intK)
{
int y = x * 2;
}
}
The difference is one deadlocks, while the other doesn't. When you
await
, you asynchronously wait by yielding control back to the calling method. When you useTask.Result
, you synchronously block on the call. This leads to a deadlock.Why? because there is something called a "Synchronization Context" involved here, which is responsible for some of the magic of executing your continuation (all the code after the first
await
) inside the same context it previously used, which in your case is the UI thread. Because you block synchronously withTask.Result
, the continuation is unable to marshal itself back onto the UI thread, since it is waiting on itself at the.Result
.Instead, use
await
as with your previous button click: