Guest Windows Apps Team Posted May 23, 2014 Posted May 23, 2014 This post was written by Gretchen Loihle and Andrew Richards in the Windows Reliability/Windows Error Reporting team. Welcome to our second post to inform Windows Store app developers about the most common failures being seen in the Windows Error Reporting (WER) telemetry across multiple Windows Store apps, and provide recommendations for how to avoid them. We invite you to read the introductory article for a more thorough discussion about WER and the availability of failure telemetry through the Store dashboard. In this segment we touch on new failures in a familiar area and introduce some new issues. In particular, we discuss JSON object deserialization, managing unexpected HTTP events, and updating Live Tiles. Before we begin, note that Microsoft has released the code for .NET 4.5.1 under the Microsoft Reference Source License (MS-RSL), and made it available to browse and download at http://ReferenceSource.microsoft.com. We’ll occasionally reference the affected code, so please feel free to examine the functions shown in the call stacks to see some of the error origins. For more on all this, see these additional resources: How to browse the .NET Reference Source (channel9 video, 02:24) Browse the .NET Reference Source (channel9 video, 27:32) .NET Compiler Platform (“Roslyn”) developer center .NET Compiler Platform (“Roslyn”) on Codeplex Microsoft open sources .NET compiler platform “Roslyn” and announces open source .NET Foundation initiative JSON parsing failures Newtonsoft.Json.dll!Newtonsoft.Json.JsonTextReader.ParseValue The talented engineers contributing to the Newtonsoft JSON framework at Json.Net have produced a free framework for transmitting objects using the JSON (JavaScript Object Notation) model. Because these libraries are free, open source, and simple to use, they have become extremely popular, and we see them increasingly bundled with many Windows Store apps. Unfortunately, these libraries often take the blame for failures that occur when handling corrupted or invalid objects, even when they are not at fault. The call stack below shows one example of this failure, where an invalid sequence of characters was read while deserializing an object. 0:020> !pe Exception object: 000000f0a1cfd838 Exception type: Newtonsoft.Json.JsonReaderException Message: Unexpected character encountered while parsing value: <. Path '', line 0, position 0. InnerException: <none> StackTrace (generated): SP IP Function 000000F0BAEECE20 00007FF82E489BC4 Newtonsoft_Json_ni!Newtonsoft.Json.JsonTextReader.ParseValue()+0xd51e4 000000F0BAEECEA0 00007FF82E3B39A0 Newtonsoft_Json_ni!Newtonsoft.Json.JsonTextReader.ReadInternal()+0x40 000000F0BAEECEF0 00007FF82E3B38AC Newtonsoft_Json_ni!Newtonsoft.Json.JsonTextReader.Read()+0x1c 000000F0BAEECF20 00007FF82E3C1F3D Newtonsoft_Json_ni!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(Newtonsoft.Json.JsonReader, Newtonsoft.Json.Serialization.JsonContract, Boolean)+0xed 000000F0BAEECF90 00007FF82E48B68F Newtonsoft_Json_ni!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(Newtonsoft.Json.JsonReader, System.Type, Boolean)+0xcdf5f 000000F0BAEED040 00007FF82E3AF6BB Newtonsoft_Json_ni!Newtonsoft.Json.JsonSerializer.DeserializeInternal(Newtonsoft.Json.JsonReader, System.Type)+0x22b 000000F0BAEED0D0 00007FF82E3A940D Newtonsoft_Json_ni!Newtonsoft.Json.JsonConvert.DeserializeObject[[system.__Canon, mscorlib]](System.String, Newtonsoft.Json.JsonSerializerSettings)+0xbd 000000F0BAEED120 00007FF82DCF9D3C xxxxxxxx_xxxxxx_Common_ni!xxxxxxxx.xxxxxx.Common.Models.Feeds+<UpdateFeedsFromWebAsync>d__23.MoveNext()+0x32c 000000F0BAEE8550 00007FF83C691CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 000000F0BAEE8590 00007FF83C691BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 000000F0BAEE85C0 00007FF82DCF99AB xxxxxxxx_xxxxxx_Common_ni!xxxxxxxx.xxxxxx.Common.Models.Feeds+<UpdateFeedsFromWebIfNeededAsync>d__14.MoveNext()+0x1ab 000000F0BAEE5E90 00007FF83C691CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 000000F0BAEE5ED0 00007FF83C691BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 000000F0BAEE5F00 00007FF8522C681F xxxxxxxx_xxxxxx_BackgroundTask_ni!xxxxxxxx.xxxxxx.BackgroundTask.TileUpdateBackgroundTask+<Run>d__0.MoveNext()+0x16f StackTraceString: <none> HResult: 80131500 80131500 = COR_E_EXCEPTION “General Exception” A review of a large number of crash dumps from the WER telemetry shows that most of the failures occur while deserializing objects, often in background tasks. This reinforces the belief that any content delivered from a remote source must be treated with suspicion, and apps should always protect themselves against invalid, unexpected, and corrupted content. Not surprisingly, the recommendation for this failure is to wrap calls that use the Newtonsoft JSON libraries with try/catch blocks, both in app code and background tasks. A decision can then be made on whether or not the app should continue, based on how crucial the objects are to app execution. Additional resources: Json.NET Newtonsoft.Json JsonTextReader.cs file (CodePlex) Newtonsoft.Json JsonTextReader.cs file (GitHub) HTTP request failures The next two failures are seen while executing HTTP requests. While these are somewhat similar to the System.Net.Http.HttpClientHandler.GetResponseCallback errors discussed in the previous article (caused by name resolution failures), the underlying causes here are a bit different. Like the JSON failures, these errors are seen most frequently in background tasks. mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd These failures occur when the app has not implemented a task cancellation handler. The exception type and message on the outer exception, plus the information in the inner exception, shows that the web request has actually been cancelled. The call stack below shows both exceptions, followed by the matching code from ReferenceSource that shows why the exception was thrown. Note that System.Net.HttpWebRequest.EndGetReponse is throwing the first exception when it detects that the EndCalled has already been set on the async web result. This was set earlier as part of cancelling the web request. 0:012> !pe -nested Exception object: 01e82a34 Exception type: System.Threading.Tasks.TaskCanceledException Message: A task was canceled. InnerException: <none> StackTrace (generated): SP IP Function 0415E6D8 65EBE4E8 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xa68e44 0415E6E8 6545569D mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35 0415E6F4 65EBDFDD mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task)+0xa69455 0415E6F8 01C30B47 xxxxxxxx_Background!Unknown+0x3ef 0415E45C 65B0EACB mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()+0x17 0415E464 65EBE4CC mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xa68e28 0415E474 6545569D mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35 0415E480 01C3046C xxxxxxxx_Background!Unknown+0xb4 0415E1F0 65B0EACB mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()+0x17 0415E1F8 65EBE4CC mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xa68e28 0415E208 6545569D mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35 0415E214 01C30236 xxxxxxxx_Background!Unknown+0xae StackTraceString: <none> HResult: 8013153b 8013153b = >COR_E_OPERATIONCANCELED “The operation was cancelled” Nested exception ------------------------------------------------------------- Exception object: 01e808bc Exception type: System.Net.WebException Message: The request was aborted: The request was canceled. InnerException: <none> StackTrace (generated): SP IP Function 0415ED3C 64F62E93 System_ni!System.Net.HttpWebRequest.EndGetResponse(System.IAsyncResult)+0x6226bf 0415ED50 5A27E721 System_Net_Http_ni!System.Net.Http.HttpClientHandler.GetResponseCallback(System.IAsyncResult)+0x41 StackTraceString: <none> HResult: 80131509 80131509 = COR_E_INVALIDOPERATION “An operation is not legal in the current state” From http://referencesource.microsoft.com/#System/net/System/Net/HttpWebRequest.cs#10e37e4a3f52a590 /// <devdoc> /// <para>Retreives the Response Result from an HTTP Result after an Async operation has completed</para> /// </devdoc> public override WebResponse EndGetResponse(IAsyncResult asyncResult) { #if DEBUG using (GlobalLog.SetThreadKind(ThreadKinds.User)) { #endif GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(asyncResult)); if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetResponse", ""); // // parameter validation // if (asyncResult==null) { throw new ArgumentNullException("asyncResult"); } LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult; if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) { throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult"); } if (castedAsyncResult.EndCalled) { throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetResponse")); } HttpWebResponse httpWebResponse = castedAsyncResult.InternalWaitForCompletion() as HttpWebResponse; castedAsyncResult.EndCalled = true; if (httpWebResponse == null) { if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetResponse", castedAsyncResult.Result as Exception); NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.HttpWebRequestFailed); throw (Exception) castedAsyncResult.Result; } GlobalLog.Assert(httpWebResponse.ResponseStream != null, "HttpWebRequest#{0}::EndGetResponse()|httpWebResponse.ResponseStream == null", ValidationHelper.HashString(this)); // Otherwise it worked, so return the HttpWebResponse. GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(httpWebResponse)); if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetResponse", httpWebResponse); InitLifetimeTracking(httpWebResponse); FrameworkEventSource.Log.EndGetResponse(this); return httpWebResponse; #if DEBUG } #endif } System.Net.Http.HttpClientHandler handles the inner exception (as it is supposed to), and lets cancellation and cleanup continue for the task. This ultimately calls into the app’s task, where the second (outer) exception occurs because the app’s task is not catching the System.Threading.Tasks.TaskCanceledException exception. The outer exception fails in mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ValidateEndwhen checking to see if the task is wait-notification enabled, or if it has not been run to completion. If the app implements a handler for System.Threading.Tasks.TaskCanceledException, execution would actually never reach this code. The recommendation here is to expect that any asynchronous activity can be cancelled at any time, and handle the appropriate cancellation exceptions that might be passed. Additional resources: Cancellation in Managed Threads (MSDN) TaskCanceledException Class (MSDN) Task Cancellation (MSDN) How to: Cancel a Task and Its Children (MSDN) System.dll!System.Net.Sockets.Socket.EndConnect This failure is something of a catch-all for a variety of networking-related issues, so there is no specific recommendation for resolution. But the underlying causes serve as a good demonstration of the variety of environments the app might be running in, and show why defensive programming is so important. In this case, the inner exception shows that a managed network socket call is surfacing an error returned from the lower network layers when trying to connect to a network endpoint. 0:012> !pe Exception object: 000000915edfb3b0 Exception type: System.Net.WebException Message: Unable to connect to the remote server InnerException: System.Net.Sockets.SocketException, Use !PrintException 000000915edf6a70 to see more. StackTrace (generated): SP IP Function 0000009177A9E8D0 00007FFFCDA810E7 System_ni!System.Net.HttpWebRequest.EndGetResponse(System.IAsyncResult)+0x7e6357 0000009177A9E930 00007FFFCEAAF313 mscorlib_ni!System.Threading.Tasks.TaskFactory`1[[system.__Canon, mscorlib]].FromAsyncCoreLogic(System.IAsyncResult, System.Func`2<System.IAsyncResult,System.__Canon>, System.Action`1<System.IAsyncResult>, System.Threading.Tasks.Task`1<System.__Canon>, Boolean)+0x63 0000009177A9E280 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 0000009177A9E2C0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 0000009177A9E2F0 00007FFFE000E1F4 xxxxxx_xxxxxxxxxx_ni!xxxxxx.xxxxxxxxxx.xxx.xxx+<ExecuteRequestAsync>d__0.MoveNext()+0x374 0000009177A9BC10 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 0000009177A9BC50 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 0000009177A9BC80 00007FFFE000DA9A xxxxxx_xxxxxxxxxx_ni!xxxxxx.xxxxxxxxxx.xxx.xxx+<LoadResponseAsync>d__0`1[[system.__Canon, mscorlib]].MoveNext()+0x1da 0000009177A995A0 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 0000009177A995E0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 0000009177A99610 00007FFFE000DDB1 xxxxxx_xxxxxxxxxx_ni!xxxxxx.xxxxxxxxxx.xxx.xxx+<LoadAsync>d__9`1[[system.__Canon, mscorlib]].MoveNext()+0x171 0000009177A96E80 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 0000009177A96EC0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 0000009177A96EF0 00007FFFCEACBF71 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter`1[[system.__Canon, mscorlib]].GetResult()+0x31 0000009177A96F20 00007FFFE0D38AEB xxxxxx_BackgroundTasks_ni!xxxxxx.BackgroundTasks.TileUpdater+<DoChange>d__4.MoveNext()+0x1bb 0000009177A947A0 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90 0000009177A947E0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54 0000009177A94810 00007FFFE0D39200 xxxxxx_BackgroundTasks_ni!xxxxx.BackgroundTasks.TileUpdater+<Run>d__f.MoveNext()+0x140 StackTraceString: <none> HResult: 80131509 There are nested exceptions on this thread. Run with -nested for details 80131509 = COR_E_INVALIDOPERATION “An operation is not legal in the current state” 0:012> !PrintException /d 000000915edf6a70 Exception object: 000000915edf6a70 Exception type: System.Net.Sockets.SocketException Message: An attempt was made to access a socket in a way forbidden by its access permissions InnerException: <none> StackTrace (generated): SP IP Function 0000009177A9EE90 00007FFFCDA5AF78 System_ni!System.Net.Sockets.Socket.EndConnect(System.IAsyncResult)+0x82e098 0000009177A9EEF0 00007FFFCD229262 System_ni!System.Net.ServicePoint.ConnectSocketInternal(Boolean, System.Net.Sockets.Socket, System.Net.Sockets.Socket, System.Net.Sockets.Socket ByRef, System.Net.IPAddress ByRef, ConnectSocketState, System.IAsyncResult, System.Exception ByRef)+0x162 StackTraceString: <none> HResult: 80004005 80004005 = Unspecified error While this specific example implies a conflict between socket use and access permissions, examination of a large set of dumps from the WER telemetry shows a variety of error messages being returned: “No connection could be made because the target machine actively refused it” “An attempt was made to access a socket in a way forbidden by its access permissions” “A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond” These errors can be caused by a number of things in the user’s environment, most of them beyond the developer’s control. For example: Firewall settings Antivirus blocking ports The port is already in use The port number is incorrect The machine has too many open connections Other issues in the user environment (restricted network access settings, router configuration, etc.) It’s important to recognize that your app may be run in a huge variety of networking environments, and handle network connection failures gracefully. For example, a polite message stating that the network is unavailable at the moment delivers a very professional impression to the user. If sufficiently important, you may even be able to offer a list of suggestions or troubleshooting items to check. Live Tile failures Windows.UI.dll!Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForApplication Windows.UI.dll!Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForSecondaryTile Many apps use tile updates to convey updates and status changes. Tile updates are often implemented as background tasks that run on a scheduled basis, or when some triggering event occurs. This failure occurs when an app (or background task) attempts to update a tile using the underlying notification system. The failure indicates that the system was unable to obtain a valid application identifier. 0:006> !pe Exception object: 023b0000 Exception type: System.Exception Message: <Invalid Object> InnerException: <none> StackTrace (generated): SP IP Function 0840EFE0 00000000 Windows_UI_ni!Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForApplication()+0x1 0840F008 0D683A88 xxxxxxxx!UNKNOWN+0x1c 0840F018 54361154 mscorlib_ni!System.Threading.Tasks.Task.InnerInvoke()+0x4c 0840F030 54361096 mscorlib_ni!System.Threading.Tasks.Task.Execute()+0x22 04A9F8F0 543662FE mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x66 04A9F900 54366290 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x38 04A9F930 0AFE7954 xxxxxxxx!UNKNOWN+0x384 04A9F9D8 54738A92 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(System.Object)+0x36 04A9F9F8 63D42B7C System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x18 StackTraceString: <none> HResult: 803e0102 0:006> !error 803e0102 0x803e0102 = WPN_E_INVALID_APP “The application identifier provided is invalid” We’ve found two scenarios that cause this failure. The first is during app development when running the app in the simulator in Visual Studio. This error may be thrown when updating tiles. The recommendation is to run the app under the Local Machine setting, as seen below. Secondly, this failure can occur when the underlying notification platform is not available on the user’s machine. If the notification platform has encountered an issue that caused it to terminate, it causes tile notification and updating to fail as well. The call to TileUpdateManager.CreateTileUpdaterForApplication normally retrieves the package full name, creates a notification endpoint, and performs package and app name validation for the notification subsystem. Problems with either of the last two steps can cause “The application identifier provided is invalid” to be returned, generating this exception. Additionally, this failure can also occur when using secondary tiles and calling TileUpdateManager.CreateTileUpdaterForSecondaryTile to change the content or appearance of a secondary tile. Make sure the secondary tile is being referenced correctly with the appropriate tileID, and that the TileDisplayAttributes are set correctly. Please see the forum post, Can’t update secondary tiles, for more information. In either case, the presence of the notification system on the customer’s machine is outside the control of the app. If notifications aren’t available, inadvertently using the notification interfaces generates an exception that should be handled by the app. It’s recommended to wrap the call to CreateTileUpdaterForApplication in a try/catch block and allow the app to keep running. For most Windows Store apps, a temporary inability to update tiles should not be a fatal condition. Additional resources: Tile and tile notification overview (MSDN) Creating a great tile experience (MSDN) Secondary tiles sample (MSDN) Tile update every minute sample (MSDN code gallery) Continue reading... Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.