【问题标题】:StorageFolder.CreateFileAsync crashes when called from App.OnSuspending从 App.OnSuspending 调用 StorageFolder.CreateFileAsync 时崩溃
【发布时间】:2012-08-13 08:11:17
【问题描述】:

我的 Win RT 应用程序在 Windows 8 beta 上与 VS2012RC 一起工作,现在在 Visual Studio 和 Windows 8 Pro 的最终版本中出现了问题,只有在我设置调试器时才能在 OnSuspending 中创建/打开文件-文件创建方法的断点。

private void OnSuspending(object sender, SuspendingEventArgs e){                        
     var deferral = e.SuspendingOperation.GetDeferral();                       
     if (null != m_document) Save();
     deferral.Complete();
}

async void Save(){
    var folder = KnownFolders.DocumentsLibrary;       
    var file = await folder.CreateFileAsync(GetFileName(),Windows.Storage.CreationCollisionOption.ReplaceExisting);                

    var xDoc = GetXDocument();
    using (var stream = await file.OpenStreamForWriteAsync()){
       xDoc.Save(stream);                    
    }           
}
  • 如果我在StorageFile file = await folder.CreateFileAsync(... 上设置断点,调试器会进入 继续,一切正常。

  • 但是,如果我不设置断点,将创建文件,但是 xml 的内容不会被保存(文件为空)。

  • 如果我在StorageFile file = await folder.CreateFileAsync(... 行下方设置断点,调试器永远不会进入!

有人知道吗?我还测试了一个使用folder.OpenStreamForWriteAsync 的版本,效果完全相同。

【问题讨论】:

  • 是否有时间完成操作?
  • @mydogisbox:似乎。但是我不知道为什么。看起来 Save() 中的 await 命令不会等到创建,而是立即(或在文件创建后)从保存函数中返回。如果我在每个方法调用之后添加 Debug.WriteLine-calls,这也是我所看到的。如果没有断点,代码将永远无法到达“var xDox=GetXDocument()”调用。它在文件创建后返回(但没有例外)。

标签: windows-8 visual-studio-2012 async-await windows-store


【解决方案1】:

问题在于对 Save 方法的调用。仅等待第一部分(创建文件),第二部分(保存 XML)异步完成,因此暂停操作的延迟一直到保存过程结束。

避免此问题的可能解决方案是明确等待保存操作完成。这可以通过将 OnSuspending-method 声明为aysnc 然后使用 await 关键字等待保存操作的完成来完成(请注意 Save-method 的 Task 返回类型)。

private async void OnSuspending(object sender, SuspendingEventArgs e){                        
     var deferral = e.SuspendingOperation.GetDeferral();                       
     if (null != m_document) await Save();
     deferral.Complete();
}

async Task Save(){
    var folder = KnownFolders.DocumentsLibrary;       
    var file = await folder.CreateFileAsync(GetFileName(),Windows.Storage.CreationCollisionOption.ReplaceExisting);                

    var xDoc = GetXDocument();
    using (var stream = await file.OpenStreamForWriteAsync()){
       xDoc.Save(stream);                    
    }           
}

我希望这篇文章可以帮助陷入同样陷阱的其他人(我想知道为什么 w8 的 beta 版没有出现问题,但我认为 MS 已经优化了应用程序终止过程,因此有在暂停过程之后进行意外工作的时间更少)...

【讨论】:

  • 最后别忘了给deferral.Complete();打电话。
  • @mydogisbox:谢谢,但是“deferall.Commit()”一直在,看看 OnSuspending 的实现。我只删除了 try/finally 以使示例更小。问题不在于完整,而在于 XML 的序列化。在我的初始例程(保存)中,我没有注意到该方法部分将异步执行(参见“等待文件夹。创建...”之后的代码)。解决方案是等待整个方法完成(参见 OnSuspending 中的 await 和 Save() 的返回类型“Task”)。
【解决方案2】:

你的时间不多了。您开始时大约需要 5 秒,但如果您不声明将使用它,那么您的时间将被缩短。试试这个:

private async void OnSuspending(object sender, SuspendingEventArgs e)
{
    var deferral = e.SuspendingOperation.GetDeferral();
    try
    {
        await Task.Delay(1000);
        Debug.WriteLine("Done");
    }
    finally
    {
        deferral.Complete();
    }
}

请参阅here 了解更多详情。官方文档见here

注意如果您需要在您的应用正在运行时进行异步工作 暂停,您需要将暂停的完成推迟到之后 你的工作完成了。您可以使用 GetDeferral 方法 SuspendingOperation 对象(可通过事件参数获得)延迟 暂停完成,直到您调用 Complete 方法之后 返回 SuspendingDeferral 对象。

【讨论】:

  • 感谢您的回答!可悲的是,它并没有解决问题。如果您查看我的代码示例,我已经推迟了暂停,为了示例的简单性,我只删除了所有异常处理。不过没关系。
  • 我发现了问题。请查看我的回答并再次感谢您的帖子。
  • @HCL 我给出的解决方案正是你所需要的……我只是无意中省略了两个关键部分……我现在把它们放回去了。
猜你喜欢
  • 2019-02-22
  • 2016-02-11
  • 2018-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
相关资源
最近更新 更多