Victor Ionescu
Victor Ionescu

Reputation: 2019

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?

Upvotes: 0

Views: 851

Answers (3)

Minh Nguyen
Minh Nguyen

Reputation: 2201

To avoid deadlock, try this:

StorageFolder s1 = await ApplicationData.Current.LocalFolder.CreateFolderAsync("one", CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);

Upvotes: 0

Victor Ionescu
Victor Ionescu

Reputation: 2019

It turns out that i can call the async method from the constructor. In the constructor:

 var task = Task.Run(async () =>
   {
       return await CacheManagerInitializeOfflineFiles();
   });
   string dummy = task.Result;

The method in same class calling the async method that creates storage dirs:

private async Task<string> CacheManagerInitializeOfflineFiles()
{
    await CacheManager.InitializeOfflineFiles();
    return "done";
}

I really don't want to put a button "initialize application", that would be bad design :)

Upvotes: 1

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149588

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.

Upvotes: 1

Related Questions