Friday, 1 November 2013

How to make SuspensionManager.RestoreAsync in W8.1 app throw

One of the requirements for the store is that the application shouldn't close unexpectedly. So your app catches an exception, but then what?

One of the things I find really troublesome about the modern style of development is knowing what to do after an exception is thrown. Most API's don't even mention that an exception is thrown, let alone what state you might be in afterward.

For instance, many of you may be upgrading your apps from 8 to 8.1. I did, and found a very odd exception.
SuspensionManager failed
at Common.SuspensionManager.<RestoreAsync>d__9.MoveNext()
This exception had an internal exception as follows:
Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
at Windows.UI.Xaml.Controls.Frame.SetNavigationState(String navigationState)
at Common.SuspensionManager.RestoreFrameNavigationState(Frame frame)
at Common.SuspensionManager.<RestoreAsync>d__9.MoveNext()

The reason for the exception boils down to Windows.UI.Xaml.Controls.Frame.SetNavigationState being passed a serialization string that has changed format between versions of my code (for example the main window class name changed in between).

I think what actually happened was this in my specific case: I had an app that had been suspended and terminated, and then I upgraded that same app from the store. When I launched the app it failed.

This exception managed to bring my code down, and fall into the unhandled exception handler because I'd modified the internal code in my app for the logic calling SuspensionManager.RestoreAsync()

In the new vs2013 wizards, you get code like this:

if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 
// Restore the saved session state only when appropriate
await SuspensionManager.RestoreAsync();
catch (SuspensionManagerException)
//Something went wrong restoring state.
//Assume there is no state and continue

Now, given that my app saw a SuspensionManagerException, how can anyone know what the state of the rootFrame is? The code in the current App.xaml.cs generated by the wizard will blindly carry on, and do this (in the SplitApp)

if (rootFrame.Content == null) 
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(ItemsPage), e.Arguments);

in the grid app it does a similar comparison, and creates a GroupedItemsPage.

But how can we know this is safe? Could we not have a partially restored navigation stack, which will lead to another crash later? Or should I just "stop worrying and learn to love the bomb"?

No comments:

Post a Comment