// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information. using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.SignalR.Infrastructure; namespace Microsoft.AspNet.SignalR { internal static class TaskAsyncHelper { private static readonly Task _emptyTask = MakeTask(null); private static readonly Task _trueTask = MakeTask(true); private static readonly Task _falseTask = MakeTask(false); private static Task MakeTask(T value) { return FromResult(value); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Empty { get { return _emptyTask; } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task True { get { return _trueTask; } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task False { get { return _falseTask; } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task OrEmpty(this Task task) { return task ?? Empty; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task OrEmpty(this Task task) { return task ?? TaskCache.Empty; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromAsync(Func beginMethod, Action endMethod, object state) { try { return Task.Factory.FromAsync(beginMethod, endMethod, state); } catch (Exception ex) { return TaskAsyncHelper.FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromAsync(Func beginMethod, Func endMethod, object state) { try { return Task.Factory.FromAsync(beginMethod, endMethod, state); } catch (Exception ex) { return TaskAsyncHelper.FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Series(Func[] tasks, object[] state) { Task prev = TaskAsyncHelper.Empty; Task finalTask = TaskAsyncHelper.Empty; for (int i = 0; i < tasks.Length; i++) { prev = finalTask; finalTask = prev.Then(tasks[i], state[i]); } return finalTask; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static TTask Catch(this TTask task) where TTask : Task { return Catch(task, ex => { }); } #if PERFCOUNTERS public static TTask Catch(this TTask task, params IPerformanceCounter[] counters) where TTask : Task { return Catch(task, _ => { if (counters == null) { return; } for (var i = 0; i < counters.Length; i++) { counters[i].Increment(); } }); } #endif [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static TTask Catch(this TTask task, Action handler, object state) where TTask : Task { if (task != null && task.Status != TaskStatus.RanToCompletion) { if (task.Status == TaskStatus.Faulted) { ExecuteOnFaulted(handler, state, task.Exception); } else { AttachFaultedContinuation(task, handler, state); } } return task; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] private static void AttachFaultedContinuation(TTask task, Action handler, object state) where TTask : Task { task.ContinueWith(innerTask => { ExecuteOnFaulted(handler, state, innerTask.Exception); }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] private static void ExecuteOnFaulted(Action handler, object state, AggregateException exception) { // observe Exception #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE Trace.TraceWarning("SignalR exception thrown by Task: {0}", exception); #endif handler(exception, state); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static TTask Catch(this TTask task, Action handler) where TTask : Task { return task.Catch((ex, state) => ((Action)state).Invoke(ex), handler); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task ContinueWithNotComplete(this Task task, Action action) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: try { action(); return task; } catch (Exception e) { return FromError(e); } case TaskStatus.RanToCompletion: return task; default: var tcs = new TaskCompletionSource(); task.ContinueWith(t => { if (t.IsFaulted || t.IsCanceled) { try { action(); if (t.IsFaulted) { tcs.TrySetUnwrappedException(t.Exception); } else { tcs.TrySetCanceled(); } } catch (Exception e) { tcs.TrySetException(e); } } else { tcs.TrySetResult(null); } }, TaskContinuationOptions.ExecuteSynchronously); return tcs.Task; } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static void ContinueWithNotComplete(this Task task, TaskCompletionSource tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } }, TaskContinuationOptions.NotOnRanToCompletion); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static void ContinueWith(this Task task, TaskCompletionSource tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.TrySetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(null); } }, TaskContinuationOptions.ExecuteSynchronously); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static void ContinueWith(this Task task, TaskCompletionSource tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.TrySetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(t.Result); } }); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Return(this Task[] tasks) { return Then(tasks, () => { }); } // Then extesions [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Action successor) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor); default: return RunTask(task, successor); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor); default: return TaskRunners.RunTask(task, successor); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task[] tasks, Action successor) { if (tasks.Length == 0) { return FromMethod(successor); } var tcs = new TaskCompletionSource(); Task.Factory.ContinueWhenAll(tasks, completedTasks => { var faulted = completedTasks.FirstOrDefault(t => t.IsFaulted); if (faulted != null) { tcs.SetUnwrappedException(faulted.Exception); return; } var cancelled = completedTasks.FirstOrDefault(t => t.IsCanceled); if (cancelled != null) { tcs.SetCanceled(); return; } successor(); tcs.SetResult(null); }); return tcs.Task; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Action successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, arg1); default: return GenericDelegates.ThenWithArgs(task, successor, arg1); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Action successor, T1 arg1, T2 arg2) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, arg1, arg2); default: return GenericDelegates.ThenWithArgs(task, successor, arg1, arg2); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, arg1); default: return GenericDelegates.ThenWithArgs(task, successor, arg1) .FastUnwrap(); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor, T1 arg1, T2 arg2) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, arg1, arg2); default: return GenericDelegates.ThenWithArgs(task, successor, arg1, arg2) .FastUnwrap(); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result); default: return TaskRunners>.RunTask(task, t => successor(t.Result)) .FastUnwrap(); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result); default: return TaskRunners.RunTask(task, t => successor(t.Result)); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result, arg1); default: return GenericDelegates.ThenWithArgs(task, successor, arg1); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor); default: return TaskRunners.RunTask(task, successor) .FastUnwrap(); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor); default: return TaskRunners>.RunTask(task, successor) .FastUnwrap(); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Action successor) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result); default: return TaskRunners.RunTask(task, successor); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func successor) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result); default: return TaskRunners.RunTask(task, t => successor(t.Result)) .FastUnwrap(); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Then(this Task task, Func, T1, Task> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor, task, arg1); default: return GenericDelegates, T1, object>.ThenWithArgs(task, successor, arg1) .FastUnwrap(); } } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are flowed to the caller")] [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Finally(this Task task, Action next, object state) { try { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: next(state); return task; case TaskStatus.RanToCompletion: return FromMethod(next, state); default: return RunTaskSynchronously(task, next, state, onlyOnSuccess: false); } } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task RunSynchronously(this Task task, Action successor) { switch (task.Status) { case TaskStatus.Faulted: case TaskStatus.Canceled: return task; case TaskStatus.RanToCompletion: return FromMethod(successor); default: return RunTaskSynchronously(task, state => ((Action)state).Invoke(), successor); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task FastUnwrap(this Task task) { var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; return innerTask ?? task.Unwrap(); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task FastUnwrap(this Task> task) { var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; return innerTask ?? task.Unwrap(); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task Delay(TimeSpan timeOut) { #if NETFX_CORE return Task.Delay(timeOut); #else var tcs = new TaskCompletionSource(); var timer = new Timer(tcs.SetResult, null, timeOut, TimeSpan.FromMilliseconds(-1)); return tcs.Task.ContinueWith(_ => { timer.Dispose(); }, TaskContinuationOptions.ExecuteSynchronously); #endif } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Action func) { try { func(); return Empty; } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Action func, T1 arg) { try { func(arg); return Empty; } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Action func, T1 arg1, T2 arg2) { try { func(arg1, arg2); return Empty; } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func func) { try { return func(); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func> func) { try { return func(); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func func) { try { return FromResult(func()); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func func, T1 arg) { try { return func(arg); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func func, T1 arg1, T2 arg2) { try { return func(arg1, arg2); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func> func, T1 arg) { try { return func(arg); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func func, T1 arg) { try { return FromResult(func(arg)); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func> func, T1 arg1, T2 arg2) { try { return func(arg1, arg2); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] public static Task FromMethod(Func func, T1 arg1, T2 arg2) { try { return FromResult(func(arg1, arg2)); } catch (Exception ex) { return FromError(ex); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] public static Task FromResult(T value) { var tcs = new TaskCompletionSource(); tcs.SetResult(value); return tcs.Task; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] internal static Task FromError(Exception e) { return FromError(e); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] internal static Task FromError(Exception e) { var tcs = new TaskCompletionSource(); tcs.SetUnwrappedException(e); return tcs.Task; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] internal static void SetUnwrappedException(this TaskCompletionSource tcs, Exception e) { var aggregateException = e as AggregateException; if (aggregateException != null) { tcs.SetException(aggregateException.InnerExceptions); } else { tcs.SetException(e); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] internal static bool TrySetUnwrappedException(this TaskCompletionSource tcs, Exception e) { var aggregateException = e as AggregateException; if (aggregateException != null) { return tcs.TrySetException(aggregateException.InnerExceptions); } else { return tcs.TrySetException(e); } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] private static Task Canceled() { var tcs = new TaskCompletionSource(); tcs.SetCanceled(); return tcs.Task; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] private static Task Canceled() { var tcs = new TaskCompletionSource(); tcs.SetCanceled(); return tcs.Task; } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] private static Task RunTask(Task task, Action successor) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { successor(); tcs.SetResult(null); } catch (Exception ex) { tcs.SetUnwrappedException(ex); } } }); return tcs.Task; } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] private static Task RunTaskSynchronously(Task task, Action next, object state, bool onlyOnSuccess = true) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { try { if (t.IsFaulted) { if (!onlyOnSuccess) { next(state); } tcs.SetUnwrappedException(t.Exception); } else if (t.IsCanceled) { if (!onlyOnSuccess) { next(state); } tcs.SetCanceled(); } else { next(state); tcs.SetResult(null); } } catch (Exception ex) { tcs.SetUnwrappedException(ex); } }, TaskContinuationOptions.ExecuteSynchronously); return tcs.Task; } private static class TaskRunners { [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] internal static Task RunTask(Task task, Action successor) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { successor(t.Result); tcs.SetResult(null); } catch (Exception ex) { tcs.SetUnwrappedException(ex); } } }); return tcs.Task; } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] internal static Task RunTask(Task task, Func successor) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { tcs.SetResult(successor()); } catch (Exception ex) { tcs.SetUnwrappedException(ex); } } }); return tcs.Task; } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] internal static Task RunTask(Task task, Func, TResult> successor) { var tcs = new TaskCompletionSource(); task.ContinueWith(t => { if (task.IsFaulted) { tcs.SetUnwrappedException(t.Exception); } else if (task.IsCanceled) { tcs.SetCanceled(); } else { try { tcs.SetResult(successor(t)); } catch (Exception ex) { tcs.SetUnwrappedException(ex); } } }); return tcs.Task; } } private static class GenericDelegates { internal static Task ThenWithArgs(Task task, Action successor, T1 arg1) { return RunTask(task, () => successor(arg1)); } internal static Task ThenWithArgs(Task task, Action successor, T1 arg1, T2 arg2) { return RunTask(task, () => successor(arg1, arg2)); } internal static Task ThenWithArgs(Task task, Func successor, T1 arg1) { return TaskRunners.RunTask(task, () => successor(arg1)); } internal static Task ThenWithArgs(Task task, Func successor, T1 arg1, T2 arg2) { return TaskRunners.RunTask(task, () => successor(arg1, arg2)); } internal static Task ThenWithArgs(Task task, Func successor, T1 arg1) { return TaskRunners.RunTask(task, t => successor(t.Result, arg1)); } internal static Task ThenWithArgs(Task task, Func successor, T1 arg1) { return TaskRunners.RunTask(task, () => successor(arg1)); } internal static Task ThenWithArgs(Task task, Func successor, T1 arg1, T2 arg2) { return TaskRunners.RunTask(task, () => successor(arg1, arg2)); } internal static Task> ThenWithArgs(Task task, Func> successor, T1 arg1) { return TaskRunners>.RunTask(task, t => successor(t.Result, arg1)); } internal static Task> ThenWithArgs(Task task, Func, T1, Task> successor, T1 arg1) { return TaskRunners>.RunTask(task, t => successor(t, arg1)); } } private static class TaskCache { public static Task Empty = MakeTask(default(T)); } } }