locked
TryRefreshToken issue RRS feed

  • Question

  • I hit unhandled exceptions when using Microsoft.Live (5.6 at the moment, but it behaved similarly before as well).

    Root cause seems to be due to private async void TryRefreshToken(Action<LiveLoginResult> completionCallback).

    Fire-and-forget nature of void async seems to be the issue. App dies with an unhandled exception. I don't think I'm doing anything wrong, but just in case I do - PLEASE LET ME KNOW. If there is no clean workaround, then it would be great if all the async void methods are eliminated from the library in the next release.

    Some observations:

    • behavior is inconsistent. It seems that TryRefreshToken is not always called (perhaps only when token is not fresh enough)
    • to repro - turn off network and try to sync
    • another workaround is to check for connectivity upfront and pre-empt TryRefreshToken failure when there is no connection :
    ConnectionProfile connectionProfile = NetworkInformation.GetInternetConnectionProfile();
     bool hasInternet = connectionProfile != null && connectionProfile.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess;

    Here is the longer (and fairly ugly) workaround that can cover additional (more intermittent) failures:

    static class SafeAsyncInvoker
     {
         static bool unhandledExceptionHandlerRegistered;
         static CancellationTokenSource globalTokenSource = new CancellationTokenSource();
         static ConcurrentDictionary<Task, object> tasksInProgress = new ConcurrentDictionary<Task, object>();
    
        public static void Register()
         {
             if (!unhandledExceptionHandlerRegistered)
             {
                 unhandledExceptionHandlerRegistered = true;
                 App.Current.UnhandledException += App_UnhandledException;
             }
         }
    
        public static async Task<T> Invoke<T>(Func<Task<T>> a)
         {
             DebugHelper.Assert(unhandledExceptionHandlerRegistered);
             CancellationTokenSource cancelatonTokenClone = globalTokenSource;
             Task<T> innnerTask = null;
             Task outerTask = Task.Run(delegate
             {
                 innnerTask = a();
                 while (!innnerTask.IsCompleted && !cancelatonTokenClone.IsCancellationRequested)
                 {
                     innnerTask.Wait(100);
                 }
             });
    
            tasksInProgress.AddOrUpdate(outerTask, outerTask, delegate { return outerTask; });
    
            try
             {
                 await outerTask;
             }
             catch (AggregateException ex)
             {
                 throw ex.InnerException;
             }
             finally
             {
                 object dummy;
                 tasksInProgress.TryRemove(outerTask, out dummy);
            }
    
            DebugHelper.Assert(innnerTask.IsFaulted == false);
             DebugHelper.Assert(outerTask.IsFaulted == false);
    
            cancelatonTokenClone.Token.ThrowIfCancellationRequested();
             return innnerTask.Result;
         }
    
        static void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
         {
             if (tasksInProgress.Count > 0)
             {
                 CancellationTokenSource newToken = new CancellationTokenSource();
                 CancellationTokenSource oldToken = Interlocked.Exchange<CancellationTokenSource>(ref globalTokenSource, newToken);
                 oldToken.Cancel();
                 e.Handled = true;
                 return;
             }
         }
     }

    Of course, this is still not bullet proof, since completion of void async is unpredictable and will not always happen while other tasks are running. Finally, here are few call stacks with bad exceptions:

    mscorlib.dll!System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RoReportUnhandledError(System.Runtime.InteropServices.WindowsRuntime.IRestrictedErrorInfo error)    Unknown

    mscorlib.dll!System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.ReportUnhandledError(System.Exception e)            Unknown

    mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ThrowAsync(System.Exception exception, System.Threading.SynchronizationContext targetContext)          Unknown

    mscorlib.dll!System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception exception)          Unknown

    Microsoft.Live.DLL!Microsoft.Live.LiveAuthClient.TryRefreshToken()     Unknown

       at Microsoft.Live.ResourceHelper.GetString(String name)

       at Microsoft.Live.Operations.ApiOperation.CreateOperationResultFrom(WebResponse response)

       at Microsoft.Live.Operations.ApiOperation.OnWebResponseReceived(WebResponse response)

       at Microsoft.Live.Operations.WebOperation.OnGetResponseCompleted(IAsyncResult ar)

       at System.Net.LazyAsyncResult.Complete(IntPtr userToken)

       at System.Net.ContextAwareResult.CaptureOrComplete(ExecutionContext& cachedContext, Boolean returnContext)

       at System.Net.ContextAwareResult.FinishPostingAsyncOp()

       at System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)

       at Microsoft.Live.Operations.ApiOperation.OnExecute()

       at Microsoft.Live.Operations.Operation.InternalExecute()

       at Microsoft.Live.Operations.ApiOperation.OnRefreshTokenOperationCompleted(LiveLoginResult result)

       at Microsoft.Live.LiveAuthClient.<TryRefreshToken>d__e.MoveNext()

    --- End of stack trace from previous location where exception was thrown ---

       at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(Object state)

       at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()



    Thursday, May 29, 2014 2:32 AM

All replies

  • We have been having this problem as well -- using the GetAsync method of the LiveSDK will cause unhandled exceptions if you have recently disconnected.  I've been lurking for years looking for a solution -- any hope that you will fix this, Microsoft?
    Tuesday, June 2, 2015 5:40 AM