I have a strange behaviour concerning wrapping asynchronous methods in C#.
It is difficult to cut out the portion of my code that has this strange behaviour, so instead I made a test project to investigate the behaviour, and this is what I have found out.
I have a test class which has an async method that is simply a wrapper of another async method: (In my original code it is a wrapper class which contains 2 objects, which it has wrapper methods for)
public class Test
{
public async Task Delay()
{
await Task.Delay(1000);
}
}
In my test program I am running the following code from an async event handler: (In my case the Loaded event, since I am using a WPF Window)
var test = new Test();
await Task.Delay(1000);
await test.Delay();
Task.Delay(1000).Wait();
test.Delay().Wait();
All is well until the last line, which never returns.
Then I tried changing the test class to the following and the last line works:
public class Test
{
public Task Delay()
{
return Task.Delay(1000);
}
}
My question is why the first scenario does not work?
I describe this deadlock scenario in detail on my blog and in an MSDN article.
By default, when you await a task, it will capture the current "context" (SynchronizationContext.Current unless it is null, in which case it captures TaskScheduler.Current). When the async method resumes, it resumes in that context.
In your case, the UI context is captured, and your async method is attempting to resume on the UI thread after the delay completes. However, it cannot resume execution because the UI thread is blocked waiting for the task to complete.
The best solution is to use async "all the way"; in other words, don't block on async code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With