UnauthorizedAccessException in MtSuspensionManager.SaveAsync()

Oct 6, 2014 at 9:24 PM
Edited Oct 6, 2014 at 9:28 PM
Hello,
I've discovered the issue sometimes causing MtSuspensionManager to throw System.UnauthorizedAccessException.

Exception details:
Message: An exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
Additional information: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at MyToolkit.Paging.MtSuspensionManager.<SaveAsync>d__0.MoveNext()
   --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at constPlayer.App.<OnSuspending>d__4.MoveNext()
  1. Reason why the exception is thrown:
    I've discovered that when you navigate back and forth inside the app and the app can go forward, requesting the app to suspend causes E_ACCESSDENIED in SaveAsync(). My intuition tells me that if I was able to disable forward stack, it would be completely fine. I'd like to do it inside MtPage.OnNavigatingFrom() for every separate page, or globally when contructing the MtFrame, but I don't really know how to archeive it.
  2. How to replicate the issue:
    -> Open the app
    -> Navigate to new page (i think it navigating forward to self works just fine)
    -> Navigate back
    -> Force Suspend Lifecycle Event in Visual Studio.
  3. Is it enough to report this behaviour as the issue?
I'm counting on your help, guys.
Best regards.
Coordinator
Oct 6, 2014 at 9:38 PM
Edited Oct 6, 2014 at 9:40 PM
In the newest version (I think its not yet available on NuGet, only git) you can disable the forward stack (disabled by default on phone). But id like to solve the problem itself.. Ill see into the problem tomorrow...
Coordinator
Oct 6, 2014 at 9:40 PM
And thanks for reporting the error and using the library...
Oct 6, 2014 at 9:44 PM
Edited Oct 6, 2014 at 9:45 PM
Yes, I'm using the NuGet version. I think that explains much.

Well, I've done little investigation myself. If I'm correct, I believe it looks like pages in forward stack could be destroyed before SaveAsync() can retreive their state, thus causing E_ACCESSDENIED (because the object the metod wanted wouldn't exist anymore in this case). But I may be badly wrong.

After doing couple more checks, I'm quite positive it happens only when ForwardStack isn't empty, though it may be also problem with the ViewModel used by me, but I don't really know how to investigate this.

Edit: how can I import git version onto Nuget package?
Coordinator
Oct 6, 2014 at 9:51 PM
I cannot reproduce the problem with the sample app...
I think the UnauthorizedAccessException is caused by the routines to write the state to a file...
Can you download the latest source code and try to reproduce the problem with the sample app (open the solution and start the SampleWindowsStoreApp app)?
Oct 6, 2014 at 9:53 PM
Ah, I forgot to tell, It's Windows Phone 8.1 solution. I'll try to reproduce the issue on the sample app.
Coordinator
Oct 6, 2014 at 9:56 PM
Ok, ill have to check this later. My WP emulator is not working since weeks, ...
Coordinator
Oct 6, 2014 at 9:58 PM
In the newest version you have this property:

http://rsuter.com/Projects/MyToolkit/Code/html/062cbd8f-47f2-c2e0-f277-2a9241ac8ae5.htm

But ill see if i can reproduce it.. (asap)
Coordinator
Oct 6, 2014 at 10:10 PM
For your tests you should

frame.DisableForwardStack = false;

so that you can better reproduce the problem...
Oct 6, 2014 at 11:12 PM
Edited Oct 6, 2014 at 11:23 PM
I've managed to replicate the issue on a sample project for Windows Phone 8.1 Uploading, will edit as soon as it's uploaded.

Unfortunately, it looks like it's not the fault of Forward Stack. Disabling and enablig it didn't make any difference.

Here you go.

Edit: I've messed something up and now i see this exception every time when I force suspending event, not just when there is something in forward stack. :/
Coordinator
Oct 7, 2014 at 7:49 AM
Edited Oct 7, 2014 at 4:06 PM
It seems that the file gets locked and then this exception occurs...

Please try to replace the following methods in MtSuspensionManager
/// <summary>Saves the current session state. </summary>
public static async Task SaveAsync()
{
    foreach (var weakFrameReference in _registeredFrames)
    {
        MtFrame frame;
        if (weakFrameReference.TryGetTarget(out frame))
            SaveFrameNavigationState(frame);
    }

    var sessionData = new MemoryStream();
    var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
    serializer.WriteObject(sessionData, _sessionState);

    var folder = ApplicationData.Current.LocalFolder; 
    var file = await folder.CreateFileAsync(SessionStateFilename, CreationCollisionOption.ReplaceExisting);
    await FileIO.WriteBufferAsync(file, sessionData.GetWindowsRuntimeBuffer());
}

/// <summary>Restores the previously stored session state. </summary>
public static async Task RestoreAsync()
{
    var folder = ApplicationData.Current.LocalFolder;
    using (var stream = await folder.OpenStreamForReadAsync(SessionStateFilename))
    {
        var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
        _sessionState = (Dictionary<string, object>)serializer.ReadObject(stream);    
    }
            
    foreach (var weakFrameReference in _registeredFrames)
    {
        MtFrame frame;
        if (weakFrameReference.TryGetTarget(out frame))
        {
            frame.ClearValue(FrameSessionStateProperty);
            RestoreFrameNavigationState(frame);
        }
    }
}
Then check if the problem is still there...
But you have to uninstall the sample app first, because the file may already be locked...
Coordinator
Oct 7, 2014 at 4:25 PM
I think this explains the problem:

http://www.damirscorner.com/ClosingStreamsInWinRT.aspx
Oct 7, 2014 at 4:27 PM
Ah, right. So is the code you sent to me alright? I've got still E_ACCESSDENIED. :/
Coordinator
Oct 7, 2014 at 4:28 PM
Did you completely uninstall the app? Ive updated the two methods 30min ago
Oct 7, 2014 at 4:29 PM
Ah, now I see. No, I'll paste the code, try it out and reply as soon as I finish testing.
Coordinator
Oct 7, 2014 at 4:31 PM
But you need to uninstall and clean up your phone/emulator first as the file may already be locked from the previous/buggy version..
Oct 7, 2014 at 5:44 PM
Edited Oct 7, 2014 at 5:45 PM
Looks like it was a deadlock after all. Problem solved. I've had some problems with my background task, that's why it took me so long to check everything (AutoResetEvent was very badly implemented by me and I had to fix the issue).

Could you do a favour for me and upload the newest version to NuGet? :)

Edit: Keep up good work! I like your toolkit.
Edit 2: Is there some kind of way to make binary copy of ObservableCollection and write it to file?
Coordinator
Oct 7, 2014 at 6:45 PM
Ok, NuGet package v2.3.14 is live...

2: What do you mean by binary copy?

If you like the library, please follow it and review it...
Oct 7, 2014 at 7:31 PM
I meant serialization, but I've managed to do this (i didn't know that it's called serialization xD)