我正在努力观察任务延续时发生的异常。方案是我在任务中进行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.Func2[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.Task1[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
有什么想法吗?