通过等待任务或在继续时访问其异常属性,未观察到任务的异常

时间:2017-05-03 16:38:59

标签: c# xamarin xamarin.android task

我正在努力观察任务延续时发生的异常。方案是我在任务中进行api调用,并在ContinueWith上检查响应是否未经授权,如果是,那么我尝试更新auth令牌。如果更新auth令牌成功,那么我重试原始任务(api调用),如果失败则我抛出自定义AuthorizationFailedException以使任务失败。 ContinueWith有一个ObserveFailures扩展方法标记到它的末尾,它应该处理异常,但是我仍然得到异常未观察到的错误,这会导致应用程序崩溃。

代码很复杂,所以我试图在这里缩小代码:

拨打api电话:

protected virtual void ExecuteResults<TResponse> (TaskCompletionSource<QueryResponse<TResponse>> tcs, Func<Task<QueryResponse<TResponse>>> queryTask, CancellationToken token) {
            QueryResponse<TResponse> result = null;
            RenewTokensIfRequired (() => queryTask ())
                .ContinueWith (t => {
                    try {
                        result = t.Result;
                    } catch (Exception ex) {
                        ServiceLocator.Current.Resolve<ILoggingService> ().Log (CommonEnums.LogLevel.Info, "BaseDataService ExecuteAndCacheResults, ex: " + ex.ToString ());
                        if (!tcs.Task.IsCompleted)
                            tcs.SetException (ex);
                        return;
                    }
                    tcs.SetResult (result);
                }).ObserveFailures (tcs);
        }

如果api调用未经授权则处理更新auth令牌的包装器任务,如果更新auth令牌失败则抛出AuthenticationFailedException:

    public static Task<QueryResponse<TResult>> RenewTokensIfRequired<TResult> (Func<Task<QueryResponse<TResult>>> taskProvider, Func<AuthorizationContext, bool> shouldRetry = null) {
                if (shouldRetry == null)
                    shouldRetry = (context) => context.AuthorizationLevel != AuthEnums.AuthorizationLevel.None;
                return taskProvider ()
                    .ContinueWith (t => RenewTokenContinuation (t, taskProvider, shouldRetry, 1)).ObserveFailures ();
            }

    static QueryResponse<TResult> RenewTokenContinuation<TResult> (Task<QueryResponse<TResult>> task, Func<Task<QueryResponse<TResult>>> taskProvider, Func<AuthorizationContext, bool> shouldRetry, int attemptsRemaining) {
                var response = task.Result;
                if (response == null || response.HasAuthenticationFailure) {
                    if (attemptsRemaining > 0 && shouldRetry (AuthorizationContext.Current)) {
                        var context = AuthorizationContext.Current;
                        if (context.AuthorizationLevel == AuthEnums.AuthorizationLevel.Session) {
                            DataService.Auth.RenewSessionTokenAsync ().ObserveFailures ().Wait (10.Seconds ());
                            return taskProvider ()
                                .ContinueWith (retryTask => RenewTokenContinuation (retryTask, taskProvider, shouldRetry, --attemptsRemaining)).ObserveFailures ()
                                .Result;
                        }
                        if (context.AuthorizationLevel == AuthEnums.AuthorizationLevel.Device) {
                            DataService.Auth.RenewDeviceTokenAsync ().ObserveFailures ().Wait (10.Seconds ());
                            return taskProvider ()
                                .ContinueWith (retryTask => RenewTokenContinuation (retryTask, taskProvider, shouldRetry, --attemptsRemaining)).ObserveFailures ()
                                .Result;
                        }
                    }
                    ResetAuthentication ();
                }
                return response;
            }

private static void ResetAuthentication () {
            // If we make it this far, then we need to throw an AuthenticationException because we couldn't refresh a token
            AuthorizationContext.Current.SessionToken = null;
            AuthorizationContext.Current.DeviceToken = null;
            throw new AuthenticationFailedException ();
        }

然后,最后,这是ObserveFailures扩展方法,它应该处理异常,但似乎不是......

public static Task<T> ObserveFailures<T> (this Task<T> task, TaskCompletionSource<T> tcs = null) {
            task.ContinueWith (t => {
                TaskActions.LogException (t.Exception);
                if (tcs != null)
                    tcs.TrySetException (t.Exception);
            }, TaskContinuationOptions.OnlyOnFaulted);
            task.ContinueWith (t => {
                ServiceLocator.Current.Resolve<ILoggingService> ().Log (CommonEnums.LogLevel.Info, "The task was canceled");
                if (tcs != null)
                    tcs.TrySetCanceled ();
            }, TaskContinuationOptions.OnlyOnCanceled);
            return task;
        }

这是崩溃堆栈跟踪:

  

Xamarin引起的:android.runtime.JavaProxyThrowable:   System.AggregateException:未观察到任务的异常   通过等待任务或访问其Exception属性。如   结果,终结器重新抛出了未观察到的异常   线。 ---&GT; System.AggregateException:发生一个或多个错误。   ---&GT;   RPR.Mobile.Shared.Exceptions.AuthenticationFailedException:Exception   类型'RPR.Mobile.Shared.Exceptions.AuthenticationFailedException'   被扔了。在   System.Threading.Tasks.TaskAuthorization.ResetAuthentication()   [0x00017] in   /Users/justintoth/Documents/rpr-mobile/shared/Utility/Extensions/TaskExtensions.cs:310   在   System.Threading.Tasks.TaskAuthorization.RenewTokenContinuation [TResult]   (System.Threading.Tasks.Task 1[TResult] task, System.Func 1 [TResult]   taskProvider,System.Func 2[T,TResult] shouldRetry, System.Int32 attemptsRemaining) [0x0016b] in /Users/justintoth/Documents/rpr-mobile/shared/Utility/Extensions/TaskExtensions.cs:272 at System.Threading.Tasks.TaskAuthorization+<RenewTokenContinuation>c__AnonStorey2 1 [TResult]。&lt;&gt; m__0   (System.Threading.Tasks.Task 1[TResult] retryTask) [0x0001e] in /Users/justintoth/Documents/rpr-mobile/shared/Utility/Extensions/TaskExtensions.cs:261 at System.Threading.Tasks.ContinuationResultTaskFromResultTask 2 [TAntecedentResult,TResult] .InnerInvoke   ()[0x00027] in   /Users/builder/data/lanes/4468/f913a78a/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs:207   在System.Threading.Tasks.Task.Execute()[0x00016]中   /Users/builder/data/lanes/4468/f913a78a/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2502

有什么想法吗?

0 个答案:

没有答案