I'm attempting to load and read a settings file on application launch, and about 90% of the time, the await GetFileAsync("filename.xml"); never returns, thus, hanging the application.
About a quarter of the time, if I step through the code, it'll actually return and read the file.
Here's a very simplified version of the code:
App.xaml.cs:
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
FileLoader.Load().Wait();
// File-load dependent stuff
}
FileLoader.cs:
public async static Task Load()
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file;
bool fileExists = true;
try
{
// The following line (often) never returns
file = await folder.GetFileAsync("filename.xml");
{
catch
{
fileExists = false;
}
// Do stuff with loaded file
}
If I watch the Output window in Visual Studio, after awhile of waiting I get "The thread '<No Name>' (0x30c) has exited with code 0 (0x0)."
Does anyone have any idea of what's happening here?
By default, when you await a Task that has not yet completed, the method resumes on a captured context (in this case, the UI context).
So, here's why your code is failing:
OnLaunched calls Load (within the UI context).Load awaits. This causes the Load method to return an incomplete task and schedule its completion for later. This continuation is scheduled for the UI context.OnLaunched blocks on the task returned from Load. This blocks the UI thread.GetFileAsync eventually completes, and attempts to run the continuation for Load.Load waits for the UI thread to be available so it can execute in the UI context.OnLaunched is waiting for Load to complete (blocking the UI thread by doing so), and Load is waiting for the UI thread to be free. Deadlock.These best practices avoid this situation:
async methods, use ConfigureAwait(false) whenever possible. In your case, this would change await folder.GetFileAsync("filename.xml"); to await folder.GetFileAsync("filename.xml").ConfigureAwait(false);.Tasks; it's async all the way down. In other words, replace Wait with await.For more information:
async/await intro post, which includes a brief description of how Task awaiters use SynchronizationContext and introduces some best practices.Update, 2012-07-13: Incorporated this answer into a blog post.
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