StorageFolder.CreateFileAsync crashes when called from App.OnSuspending
Asked Answered
M

2

5

My Win RT application which has worked with VS2012RC on a Windows 8 beta, has now with the final versions of visual studio and windows 8 pro the problem, that creating/opening a file within OnSuspending only works if I set a debugger-breakpoint to the file creation method.

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);                    
    }           
}
  • If I set a breakpoint on StorageFile file = await folder.CreateFileAsync(..., the debugger enters the and if I continue, all works fine.

  • However if I dont set a breakpoint, the file will be created, but the content of the xml will not be saved (the file rests empty).

  • If I set a breakpoint below of the line StorageFile file = await folder.CreateFileAsync(..., the debugger never enters!

Has anyone an idea? I have also tested a version which uses folder.OpenStreamForWriteAsync, with the very same effect.

Magnification answered 16/8, 2012 at 22:21 Comment(2)
Does it maybe run out of time to finish the operation?Assent
@mydogisbox: It seems to. However I dont know why. It Looks like the await command in Save() does not wait until creation but returns immediately (or after file creation) out of the save-function. This is also what I see, if I add Debug.WriteLine-calls after every method call. Without a breakpoint, the code will never reach the "var xDox=GetXDocument()"-call. It returns after file creation (but without an exception).Magnification
M
7

The problem was the call to the Save-method. Only the first part (creation of the file) was been waited for, the second part (saving XML) was done async, and therefore the deferral of the suspending operation has not been until the end of the save process.

A possible solution to avoid this problem is to wait explicitely for the completion of the save-operation. This can be accomplished by declaring the OnSuspending-method as aysnc and then waiting for the completion of the save Operation with the await keyword (please note the Task return-type of the Save-method).

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

I hope this post helps someone else who has been fallen into the same pitfall (I'm wondering why the problem has not occured with the beta of w8, but I think that MS has optimized the application termination-process and therefore there is less time for unexpected work after the suspension-process)...

Magnification answered 17/8, 2012 at 9:18 Comment(2)
Don't forget to call deferral.Complete(); at the end.Assent
@mydogisbox: Thanks, but "deferall.Commit()" was always in, look at the implementation of OnSuspending. I only removed the try/finally to make the example smaller. The problem was not the Complete, but the serialization of the XML. In my initial routine (Save), I have not remarked that the method partially will execute asynchronous (see the code after the "await folder.Create..."). The solution was to wait to the completion of the whole method (see the await in OnSuspending and the return Type "Task" of Save()).Magnification
A
3

You're running out of time. You start out with approximately 5 seconds, but if you don't declare that you will use it then your time will be cut short. Try this:

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

See here for more details. See here for the official documentation:

Note If you need to do asynchronous work when your app is being suspended you will need to defer completion of suspend until after your work completes. You can use the GetDeferral method on the SuspendingOperation object (available via the event args) to delay completion of suspend until after you call the Complete method on the returned SuspendingDeferral object.

Assent answered 17/8, 2012 at 3:24 Comment(3)
Thank you for your answer! Sadly, it does not resolve the problem. If you look at my code example, I already defer the suspension, I only have removed all the exception handling for simplicity of the example. However it makes no difference.Magnification
I have found the problem. Please see my answer and thanks again for your post.Magnification
@Magnification the solution I gave was what you needed... I just unintentionally omitted the two key parts... I put them back in now.Assent

© 2022 - 2024 — McMap. All rights reserved.