As Windows Store app builders, we’re sure you’re aware that apps can experience a variety of failures: hangs, crashes, unavailable services and resources, and any number of unexpected operating conditions. These failures impact your customers’ experience, and if left unaddressed they can even cause customers to stop using your app or move to a competitor’s product. What you might not be aware of is that Microsoft makes this data available to help you build a more stable, reliable app that your customers will love. This post gives you a brief introduction of the Windows Error Reporting (WER) telemetry and how it’s available in the Store dashboard.
In addition, we’ll share some of the “real world best practices” guidance that have emerged from WER telemetry including insights from Windows Store apps, particularly where many apps are failing due to the same coding and design issues. We hope that this content will inform you, as a Windows Store app developer, of some of the unexpected failures that might occur post-release, and will help you build better, more reliable apps.
Windows Error Reporting
Since Windows XP, Microsoft operating systems have provided a failure reporting mechanism called Windows Error Reporting (WER). When a user opts in to allow their system to send telemetry data back to Microsoft, WER sends back crash and hang reports, including those from Windows Store apps. A dedicated telemetry system processes the error reports, collects crash and hang dumps, builds failure curves and finds the highest-hitting issues. The MSDN article How WER Collects and Classifies Error Reports offers a high-level view. Additionally, a paper from Microsoft Research titled Debugging in the (Very) Large: Ten Years of Implementation and Experience provides very in-depth information on this process.
The telemetry from WER is used not only within Microsoft, it is also shared with many partners including IHVs (hardware vendors), ISVs (software vendors), and OEMs (system manufacturers), and it is used for direct outreach for the most severe failures. The portal at http://sysdev.microsoft.com provides WER telemetry to ISVs, IHVs and OEMs in the form of metrics and failure curves that show what the top issues are, and in hang and crash dumps that can be downloaded for debugging.
The Windows Store dashboard provides this information to Windows Store app developers, along with additional metrics on download and usage data, ratings and reviews, and financial information. The Reviewing app quality page on MSDN gives a wonderful overview of how you can use telemetry to understand and resolve app failures to improve app quality. Please note that you must enable telemetry collection for your account in order to receive this data. As a Windows Store app developer, you are encouraged to visit the dashboard and view the metrics and failure data available for your apps.
Common Failures
As might be expected, the broad range of WER telemetry gives Microsoft a unique perspective on the failures affecting apps. While the Store dashboard displays failures affecting published apps for a given developer account, Microsoft can see failures across all apps, including failures that are affecting many apps simultaneously. These typically show up in two forms: failures in platform and framework binaries (such as Windows.UI.Xaml.dll), and as crashes of specific types that occur across a large variety of apps.
Failures that affect multiple apps (we’ll call them “multi-app failures” for brevity) may not cause the most crashes for any specific app, but can be significant issues when viewed across all apps. Multi-app failures discovered through the WER telemetry reveal situations where caution is needed in app design. WER telemetry can be considered an augmentation to in-house testing, as it reveals problems that occur in a very diverse population with diverse environments.
To coincide with this post, the Channel 9 Defrag Tools show has aired a number of episodes on common problems in Windows Store apps. Each episode is 15-20 minutes long and applies a common coding mistake to a Win 8.1 app sample. Please use this Channel 9 link to find all current postings.
In addition, the NT Debugging blog has also posted a technically deep article on how to debug Windows Store crash dumps to get the error code and call stack of the issue. Please read Debugging a Windows 8.1 Store App Crash Dump for details on investigating the most common form of Windows Store app crashes.
Guidance on avoiding these failures represents best practice recommendations based on actual customer experience. Implementing the two recommendations below (try/catch and null pointers) will add considerable stability to any app. With any code change, the change must be done with care so that the effect is expected and the outcome is desirable – swallowing an exception without any indication may result in a confused user: “I tapped the button but nothing happened?!”.
Best Practice – try/catch blocks
One thing we frequently see through WER telemetry is when apps don’t handle exceptions appropriately via try/catch blocks. Lots of apps assume that a network call will succeed or some XML will parse. In the real world, these (normally successful) operations will fail at times, for unpredictable reasons. It’s good to assume that the size and diversity of the Windows ecosystem could cause edge cases in your code to be executed. To have a stable app, you have to not trust the network connectivity, data integrity, or the access level of the user.
Mitigation is easy. Add a try/catch block around any code that isn’t guaranteed to succeed. You can choose to do many things with the exception. Hide it, log it, or inform the user. Continue on or gracefully fail. Consume it, throw it again, or throw it as an inner exception of a new exception you make. If it is to be thrown again, you should make sure that it will be caught elsewhere.
This code snippet from the File Access sample in the Windows 8.1 SDK shows how a System.IO.FileNotFoundException exception is handled gracefully:
try
{
if (file != null)
{
IBuffer buffer = await FileIO.ReadBufferAsync(file);
using (DataReader dataReader = DataReader.FromBuffer(buffer))
{
string fileContent = dataReader.ReadString(buffer.Length);
// ...
}
}
}
catch (FileNotFoundException)
{
// File not found exception
}
Best Practice – null pointers
Check variables for null before using them as a pointer. Don’t assume that a function is being passed a valid object, and don’t assume functions you call return a valid object. These can be a follow-on effect of handling exceptions correctly. For example, a function might normally return an object, but if an error occurs it may return a null instead of allowing an exception to be thrown.
The adapted code snippet below shows how a simple if-statement can be used to avoid a function call that would result in an ArgumentNullException exception, and an object reference that would result in a NullReferenceException exception.
if (file != null)
{
IBuffer buffer = await FileIO.ReadBufferAsync(file);
string name = file.DisplayName;
}
Specific Failures
Using Best Practices helps avoid most problems and should be applied across your entire codebase. There are some specific issues that warrant attention, though, due to their prevalence or lack of awareness. Specifically, below we go over the incorrect handling of Navigation State (suspension), HTTP Requests and XML Parsing.
Windows.UI.Xaml.Controls.Frame.GetNavigationState
One of the components where we’ve identified a significant number of crashes is Windows.UI.Xaml.dll!Windows.UI.Xaml.Controls.Frame.GetNavigationState, which serializes the app’s frame navigation history (commonly at suspend). As documented on MSDN, serialization only supports four basic data types (string, char, numeric and GUID). In some cases, apps attempt to store more complex data, and this generates an exception when attempting to serialize the navigation state. Because this exception originates within a Microsoft platform component and not app code, the failures are not surfaced on the Windows Store dashboard and many developers are unaware that their apps are behaving incorrectly and are causing these crashes.
Two examples of the failing call stacks are shown below, showing where the failure is generated while preparing to be suspended. Note that the failure occurs when retrieving the accumulated navigation history; there is no opportunity to convert to supported types after retrieval.
Example 1
Windows_UI_Xaml_ni!Windows.UI.Xaml.Controls.Frame.GetNavigationState
xxxxxxxx!xxxxx.xxxxxx.SuspensionManager.SaveFrameNavigationState
xxxxxxxx!xxxxx.xxxxxx.SuspensionManager+_SaveAsync_d__0.MoveNext
mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess
mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification
xxxxxxxx!xxxxx.App+_OnSuspending_d__a.MoveNext
mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore._ThrowAsync_b__0
system_runtime_windowsruntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore
mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
system_runtime_windowsruntime_ni!System.Threading.WinRTSynchronizationContext+Invoker._InvokeCore_b__0
mscorlib_ni!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context
mscorlib_ni!System.Threading.ExecutionContext.RunInternal
mscorlib_ni!System.Threading.ExecutionContext.Run
mscorlib_ni!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem
mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch
mscorlib_ni!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback
Example 2
Windows_UI_Xaml_4920000!Windows.UI.Xaml.Controls.Frame.GetNavigationState()+0x1
xx_xxxxx_xxxxxxx_xx!xx.xxxxx.Library.StateHelper+<SaveState>d__0.MoveNext()+0x164
mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x5e
mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
xx_xxxxxxxx_xxxxxxx_xx!xx.xxxxxxxx.xxxxxxx.App+<OnSuspending>d__6.MoveNext()+0xb1
mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(System.Object)+0x33
System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x24
mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()+0x17
System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.<InvokeCore>b__0(System.Object)+0x28
mscorlib_ni!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)+0x3e
mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0xa7
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x16
mscorlib_ni!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()+0x60
mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch()+0x10a
mscorlib_ni!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()+0x5
The recommended guidance for this scenario is to only use the supported data types as parameters when calling Frame.Navigate(TypeName, Object) or Frame.Navigate(TypeName, Object, NavigationTransitionInfo), or when directly adding a PageStackEntry to the BackStack or ForwardStack of a Frame. Note that more complex types can be used if Frame.GetNavigationState will never be called; please refer to the Dev Center documentation for additional details.
The code sample below demonstrates how the failure might be reproduced. This sample adds a page and an invalid parameter type to the navigation backstack, and will fail when Frame.GetNavigationState is called.
private void Button1Click(object sender, RoutedEventArgs e)
{
// Add a page to the Back History with a parameter that isn't basic
int[] array5 = new int[5];
var pse = new PageStackEntry(typeof(SDKTemplate.MainPage), array5, null);
this.MyFrame.BackStack.Add(pse);
}
private void Button2Click(object sender, RoutedEventArgs e)
{
// Simulate a GetNavigationState operation that would happen at Suspend
var str = this.MyFrame.GetNavigationState();
}
Additional resources:
- Frame.GetNavigationState
- Channel 9 – Defrag Tools: #74 – Windows 8.1 – Frame.GetNavigationState Crash
- MSDN: Frame.Navigate(TypeName, Object)
- MSDN: Frame.Navigate(TypeName, Object, NavigationTransitionInfo)
- How to trigger suspend, resume, and background events in Windows Store apps
- How to suspend an app (Windows Store apps using C#/VB/C++ and XAML)
System.Net.Http.HttpClientHandler.GetResponseCallback
Another example of a common failure scenario is when apps fail while making async HTTP calls via System.Net.Http.dll. The top-level error description returned is “An error occurred while sending the request”, our analysis indicates there are a wide variety of underlying causes. This is essentially a high-level “something went wrong” error that occurs when using asynchronous HTTP calls. These failures may be caused by transient network or DNS conditions; remote name resolution failure is one of the most common causes. This can be seen in crashes that are attempting to reach common URLs:
Exception type: System.Net.WebException
Message: The remote name could not be resolved: 'www.contoso.com'
This code snippet from the HttpClient sample in the Windows 8.1 SDK shows how cancellation is handled (explicitly) and how all other exceptions are handled (generically), for an HTTP request:
{
...
Uri resourceAddress = new Uri(AddressField.Text);
HttpResponseMessage response = await
httpClient.GetAsync(resourceAddress).AsTask(cts.Token);
...
}
catch (TaskCanceledException)
{
rootPage.NotifyUser("Request canceled.", NotifyType.ErrorMessage);
}
catch (Exception ex)
{
rootPage.NotifyUser("Error: " + ex.Message, NotifyType.ErrorMessage);
}
When using a System.Net.Http.HttpClient object, it is common to see a System.Net.Http.HttpRequestException exception with a System.Net.WebException inner exception.
0:012> !pe
Exception object: 0332240c
Exception type: System.Net.Http.HttpRequestException
Message: An error occurred while sending the request.
InnerException: System.Net.WebException, Use !PrintException 03321d8c to see more.
StackTrace (generated):
SP IP Function
05D8F128 6AEDCE66 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x5e
05D8F138 6AEDCDF9 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
05D8F144 6E7794C9 BackgroundTasks_ni!BackgroundTasks.TileUpdater+<Run>d__0.MoveNext()+0x3a9
05D8F8D8 6B66BC9F mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__1(System.Object)+0x33
05D8F8E0 6AE7CACA mscorlib_ni!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)+0x3e
05D8F8E8 6AE92367 mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0xa7
05D8F954 6AE922A6 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x16
05D8F968 6AE9DD60 mscorlib_ni!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()+0x60
05D8F97C 6AE9D509 mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch()+0x149
05D8F9CC 6AE9D3A5 mscorlib_ni!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()+0x5
StackTraceString: <none>
HResult: 80131500
0:012> !PrintException 03321d8c
Exception object: 03321d8c
Exception type: System.Net.WebException
Message: The remote name could not be resolved: 'www.contoso.com'
InnerException: <none>
StackTrace (generated):
SP IP Function
05D8F740 6AA281EF System_ni!System.Net.HttpWebRequest.EndGetResponse(System.IAsyncResult)+0x633017
05D8F754 55FDF131 System_Net_Http_ni!System.Net.Http.HttpClientHandler.GetResponseCallback(System.IAsyncResult)+0x41
This is a case where your app does not cause the error, but still needs to be ready to handle unanticipated error conditions. Async network calls can be expected to fail any number of ways and should always be wrapped in try/catch blocks. Your apps should protect themselves against transient DNS name resolution failures, network congestion, slow response times, server (and service) unavailability, and abrupt connection loss. These are rarely tested and caught during the development phase, as most developers will not have access to test environments that exhaustively mimic networking conditions, and corresponding user behavior. With defensive exception handling in place, your app can handle transient network conditions gracefully and wait and retry, or notify the user and let them decide whether to retry, navigate to another activity in the app, or exit.
Note that Windows 8.1 offers the new Windows.Web.Http namespace that allows you to modularize your HTTP networking code, including filters you write to manage network communication and error handling. This may allow you to separate your app and business logic from your network error handling logic, for easier network failure management. Refer to the HttpClient sample for examples of using filters.
Additional resources:
- Troubleshooting and debugging network connections (Windows Store apps)
- Channel 9 – Defrag Tools: #68 – Windows 8.1 – HTTP Request Crash
- Windows.Web.Http API
XML Parsing
When analyzing crash data specific to Windows Store apps, we’ve seen a high prevalence of CLR exception codes related to XML parsing (exceptions of type System.Xml.XmlException). Apps are encountering XML parsing failures that were not seen during app development or during certification testing. These failures are being caused by many factors, from badly formed ads and RSS feeds to corrupted XML to invalid dynamic content. At the time of this writing, System.Xml.XmlException is the second most popular cause of multi-app crashes in Windows 8.1 after System.NullReferenceException.
What is extremely important to note here is that WER telemetry frequently shows XML failures in content that is outside the control of your app. Apps that use RSS feeds or ads are particularly affected, as RSS feeds and ad services occasionally deliver content that is auto-generated or malformed, causing app crashes during parsing. Try/catch blocks around the XML parsing code would permit your app to handle unexpected content gracefully. In the same manner as the networking failures mentioned above, defensive coding is especially important when consuming content that does not come from a source you control.
Parsing errors are the most common cause of XML failures. These appear in the WER telemetry in a variety of ways, due to the prevalence of XML parsing code in various forms. Reasons for failures can include unexpected tokens, invalid root data, unclosed elements, and failed XML character decodes. For reference, you can review this list of XML parsing exception codes.
Two sample call stacks are shown below.
Example 1
0:016> !pe
Exception object: 02d344ec
Exception type: System.Exception
Message: Undtagelse fra HRESULT: 0xC00CE50D <-- A semicolon character was expected
InnerException: <none>
StackTrace (generated):
SP IP Function
00000000 00000001 Windows_Data_ni!Windows.Data.Xml.Dom.XmlDocument.LoadXml(System.String)+0x2
0554F700 5CA58965 xxxxxxxxxxx_ni!xxxxxxxxxxx.xxxxxxxxxxxxxx.GetPermissions(Byte[])+0x75
0554F720 5CA6D1C0 xxxxxxxxxxx_ni!xxxxxxxxxxx.xxxx.AsyncWebRequest+<Start>d__1.MoveNext()+0x10c
0554F804 65C5BC63 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__0(System.Object)+0x33
0554F80C 5A7D13D4 System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x24
0997F884 65B61887 mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()+0x17
0997F88C 5A7FE728 System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.<InvokeCore>b__0(System.Object)+0x28
0997F890 6546CACA mscorlib_ni!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)+0x3e
0997F898 65482367 mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0xa7
0997F904 654822A6 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x16
0997F918 6548DD60 mscorlib_ni!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()+0x60
0997F92C 6548D509 mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch()+0x149
0997F97C 6548D3A5 mscorlib_ni!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()+0x5
Example 2
Exception object: 025f62c0
Exception type: System.Xml.XmlException
Message: <Invalid Object>
InnerException: <none>
StackTrace (generated):
SP IP Function
04CFF3A0 6DEB4FCF System_Runtime_Serialization_ni!System.Runtime.Serialization.Json.JsonEncodingStreamWrapper.ReadEncoding(Byte, Byte)+0x1d31b7
04CFF3B0 6DCE1DB7 System_Runtime_Serialization_ni!System.Runtime.Serialization.Json.JsonEncodingStreamWrapper.ReadEncoding()+0x4b
04CFF3C4 6DCE1C36 System_Runtime_Serialization_ni!System.Runtime.Serialization.Json.JsonEncodingStreamWrapper.InitForReading(System.IO.Stream, System.Text.Encoding)+0x4a
04CFF3F0 6DCE1BE4 System_Runtime_Serialization_ni!System.Runtime.Serialization.Json.JsonEncodingStreamWrapper..ctor(System.IO.Stream, System.Text.Encoding, Boolean)+0x40
04CFF40C 6DCE1B7F System_Runtime_Serialization_ni!System.Runtime.Serialization.Json.XmlJsonReader.SetInput(System.IO.Stream, System.Text.Encoding, System.Xml.XmlDictionaryReaderQuotas, System.Xml.OnXmlDictionaryReaderClose)+0x4f
04CFF42C 6DCE1B1C System_Runtime_Serialization_ni!System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject(System.IO.Stream)+0x60
04CFF444 0BF242E6 xxxxxxxx!UNKNOWN+0x146
04CFF10C 723DD17A mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x5e
04CFF11C 723DD115 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
04CFF128 0BF219FD xxxxxxxx!UNKNOWN+0x29d
04CFEE00 723DD17A mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x5e
04CFEE10 723DD115 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
04CFEE1C 0BF204EC xxxxxxxx!UNKNOWN+0xbc
< ... >
04CFF564 72B5458F mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(System.Object)+0x33
04CFF56C 6E98F994 System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x24
StackTraceString: <none>
HResult: 80131940
Note: throws "invalid bytes", including two null unicode bytes (0x00 0x00)
A second form of XML failures shows up when dealing with XML as streams. Serializing to or from a stream is a common source of exceptions, particularly when translating to or from JSON. The exception codes can include any of the XML parsing failures seen earlier, plus serialization-specific failures like unexpected end-of-file and encoding issues.
The recommendation when using XML streams is to envision all of the things that can go wrong with streams – particularly remote streams – and practice defensive coding. For example, the underlying connection may be slow, or the network connection might terminate, or a shared FileStream object might be subject to unexpected stream position bugs.
The code sample below demonstrates a failure that can occur when reading from a FileStream, and reproduces a commonly seen call stack.
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string fileName = @".SerializeTest.xml";
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
Person p1 = new Person("Cool", "Joe", 101);
FileStream writer = new FileStream(fileName, FileMode.Create);
ser.WriteObject(writer, p1);
writer.Close();
FileStream fs = File.OpenRead(fileName);
// Note that this reads the entire file and positions the stream at EOF
XmlReader reader = XmlReader.Create(fs);
reader.MoveToContent();
while (reader.Read())
{
}
// Throws an “unexpected end of file” exception
Person p2 = (Person)ser.ReadObject(fs);
fs.Close();
}
// You must apply a DataContractAttribute or SerializableAttribute
// to a class to have it serialized by the DataContractSerializer.
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
class Person : IExtensibleDataObject
{
[DataMember()]
public string FirstName;
[DataMember]
public string LastName;
[DataMember()]
public int ID;
public Person(string newfName, string newLName, int newID)
{
FirstName = newfName;
LastName = newLName;
ID = newID;
}
private ExtensionDataObject extensionData_Value;
public ExtensionDataObject ExtensionData
{
get
{
return extensionData_Value;
}
set
{
extensionData_Value = value;
}
}
}
}
}
Wrapping the stream call in a try/catch block will let the app handle the failure without crashing.
try
{
Person p2 = (Person)ser.ReadObject(fs);
...
}
catch (System.Xml.XmlException)
{
if (fs.Position == fs.Length) // at EOF
{
// Decide what to do
}
}
catch (Exception e)
{
// Decide what to do
}
Additional resources:
Wrap-Up
The Windows Error Reporting telemetry contains an amazing wealth of information on how things can go wrong, and – in a backwards sort of way – gives a good roadmap on how to build a robust, reliable Windows Store app. We hope that providing this information is useful to you, and helps trigger your thinking and understanding about how your apps behave in the wild. We look forward to presenting more insights in future posts.
Happy Coding!
–Gretchen Loihle and Andrew Richards
Windows Reliability/Windows Error Reporting