StorageFolder.CreateFolderAsync 中的奇怪行为

strange behaviour in StorageFolder.CreateFolderAsync

我正在为 windows 商店应用程序做一些事情,这是一个通用应用程序项目,我正在 Windows 8.1 笔记本和 windows 8.1 Surface Pro 3 上进行调试.

我正在尝试在 ApplicationData.Current.LocalFolder 中创建一些嵌套文件夹。 从主屏幕的构造函数中,我调用

CacheManager.InitializeOfflineFiles().Wait();

CacheManager.InitializeOfflineFiles() 的代码是

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);
    }
}

当我调试它时,它并没有通过创建文件夹 "two"。没有异常记录,什么都没有。此外,当我 运行 这没有调试 (Ctrl + F5) 时,结果相同,只有 dir "one/two" 在本地存储中创建。

这是对异步编程的误解吗?

这个:

CacheManager.InitializeOfflineFiles().Wait();

导致您的应用死锁。这就是您看到 "hanging" 行为的原因。奇怪的是,您似乎看到正在创建文件夹 1 和 2,因为我认为在执行第一个 await 时这应该会死锁。

这就是你 shouldn't block on async code 的原因。

由于构造函数不能异步,请改用 "Initialize Pattern" (or other known async initalization patterns) 来执行您的异步代码:

public Task InitializeAsync()
{
    return InitializeOfflineFilesAsync()
}

然后从您的代码中,从 async 上下文方法调用它,也许是 事件处理程序:

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

故事的寓意是,不要通过构造函数调用异步方法。

事实证明,我可以从构造函数中调用异步方法。 在构造函数中:

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

相同class中的方法调用创建存储目录的异步方法:

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

我真的不想放一个按钮 "initialize application",那将是糟糕的设计:)

要避免死锁,试试这个:

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