Victor Ionescu Victor Ionescu - 2 months ago 16
C# Question

strange behaviour in StorageFolder.CreateFolderAsync

I'm doing something for a windows store app, it's an Universal App project and I'm debugging on a Windows 8.1 notebook and a windows 8.1 Surface Pro 3.

I'm trying to create some nested folders in ApplicationData.Current.LocalFolder.
From the constructor of the main screen, I call

CacheManager.InitializeOfflineFiles().Wait();


and the code for CacheManager.InitializeOfflineFiles() is

public static async Task InitializeOfflineFiles()
{
try
{
StorageFolder s1 = await ApplicationData.Current.LocalFolder.CreateFolderAsync("one", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder one");
StorageFolder s2 = await s1.CreateFolderAsync("two", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder two");
StorageFolder s3 = await s2.CreateFolderAsync("three", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder three");
StorageFolder s4 = await s3.CreateFolderAsync("four", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder four");
}
catch (Exception e)
{
Debug.WriteLine("Windows doesn't love you. Exception: " + e.Message);
}
}


When I debug this, it doesn't get past creating folder "two". No exception logged, no nothing. Also, when I run this without debugging (Ctrl + F5), same result, only dir "one/two" gets created in the local storage.

Is this a case of misunderstanding async programming?

Answer

This:

CacheManager.InitializeOfflineFiles().Wait();

Is causing your app to deadlock. This is why you're seeing the "hanging" behavior. It is peculiar that you seem to be seeing folder 1 & 2 being created, as i assume this should deadlock when the first await is executed.

This is the reason you shouldn't block on async code.

Since constructors can't be async, use the "Initialize Pattern" (or other known async initalization patterns) instead to execute your async code:

public Task InitializeAsync()
{
    return InitializeOfflineFilesAsync()
}

And from your code, call this from an async context method, perhaps an event handler:

public async void SomeButtonClickEventHandler()
{
    await InitializeAsync();
}

The moral of the story is, don't call asynchronous methods via your constructor.