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);
.Task
s; 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.