namespace Microshaoft { using System; using System.Threading.Tasks; using System.Web; public class HttpTaskAsyncHandler : IHttpAsyncHandler { public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { throw new NotSupportedException(); } public Task ProcessRequestAsync(HttpContextBase context) { // Microshaoft. //TaskAsyncHelper. return null; } IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { Task task = ProcessRequestAsync(new HttpContextWrapper(context)); var retVal = new TaskWrapperAsyncResult(task, extraData); if (task == null) { // No task, so just let ASP.NET deal with it return null; } if (cb != null) { // The callback needs the same argument that the Begin method returns, which is our special wrapper, not the original Task. task.ContinueWith(_ => cb(retVal)); } return retVal; } void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) { if (result == null) { throw new ArgumentNullException("result"); } // The End* method doesn't actually perform any actual work, but we do need to maintain two invariants: // 1. Make sure the underlying Task actually *is* complete. // 2. If the Task encountered an exception, observe it here. // (The Wait method handles both of those.) var castResult = (TaskWrapperAsyncResult)result; castResult.Task.Wait(); } } } namespace Microshaoft { using System; using System.Threading; using System.Threading.Tasks; internal sealed class TaskWrapperAsyncResult : IAsyncResult { internal TaskWrapperAsyncResult(Task task, object asyncState) { Task = task; AsyncState = asyncState; } public object AsyncState { get; private set; } public WaitHandle AsyncWaitHandle { get { return ((IAsyncResult)Task).AsyncWaitHandle; } } public bool CompletedSynchronously { get { return ((IAsyncResult)Task).CompletedSynchronously; } } public bool IsCompleted { get { return ((IAsyncResult)Task).IsCompleted; } } public Task Task { get; private set; } } } namespace Microshaoft { using System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; public static class TaskAsyncHelper { private static readonly Task _emptyTask = MakeEmpty(); private static Task MakeEmpty() { return FromResult<object>(null); } public static Task Empty { get { return _emptyTask; } } public static TTask Catch<TTask>(this TTask task) where TTask : Task { if (task != null && task.Status != TaskStatus.RanToCompletion) { task.ContinueWith(innerTask => { var ex = innerTask.Exception; // observe Exception #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE Trace.TraceError("SignalR exception thrown by Task: {0}", ex); #endif }, TaskContinuationOptions.OnlyOnFaulted); } return task; } public static TTask Catch<TTask>(this TTask task, Action<Exception> handler) where TTask : Task { if (task != null && task.Status != TaskStatus.RanToCompletion) { task.ContinueWith(innerTask => { var ex = innerTask.Exception; // observe Exception #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE Trace.TraceError("SignalR exception thrown by Task: {0}", ex); #endif handler(ex); }, TaskContinuationOptions.OnlyOnFaulted); } return task; } public static void ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } }, TaskContinuationOptions.NotOnRanToCompletion); } public static void ContinueWith(this Task task, TaskCompletionSource<object> tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.TrySetException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(null); } }); } public static void ContinueWith<T>(this Task<T> task, TaskCompletionSource<T> tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.TrySetException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(t.Result); } }); } /// <summary> /// Passes a task returning function into another task returning function so that /// it can decide when it starts and returns a task that completes when all are finished /// </summary> public static Task Interleave<T>(Func<T, Action, Task> before, Func<Task> after, T arg) { var tcs = new TaskCompletionSource<object>(); var tasks = new[] { tcs.Task, before(arg, () => after().ContinueWith(tcs)) }; return tasks.Return(); } public static Task Return(this Task[] tasks) { return Then(tasks, () => { }); } // Then extesions public static Task Then(this Task task, Action successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor); default: return RunTask(task, successor); } } public static Task<TResult> Then<TResult>(this Task task, Func<TResult> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor); default: return TaskRunners<object, TResult>.RunTask(task, successor); } } public static Task Then(this Task[] tasks, Action successor) { if (tasks.Length == 0) { return FromMethod(successor); } var tcs = new TaskCompletionSource<object>(); Task.Factory.ContinueWhenAll(tasks, completedTasks => { var faulted = completedTasks.FirstOrDefault(t => t.IsFaulted); if (faulted != null) { tcs.SetException(faulted.Exception); return; } var cancelled = completedTasks.FirstOrDefault(t => t.IsCanceled); if (cancelled != null) { tcs.SetCanceled(); return; } successor(); tcs.SetResult(null); }); return tcs.Task; } public static Task Then<T1>(this Task task, Action<T1> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1); default: return GenericDelegates<object, object, T1, object>.ThenWithArgs(task, successor, arg1); } } public static Task Then<T1, T2>(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1, arg2); default: return GenericDelegates<object, object, T1, T2>.ThenWithArgs(task, successor, arg1, arg2); } } public static Task Then<T1>(this Task task, Func<T1, Task> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1).FastUnwrap(); default: return GenericDelegates<object, Task, T1, object>.ThenWithArgs(task, successor, arg1) .FastUnwrap(); } } public static Task Then<T1, T2>(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1, arg2).FastUnwrap(); default: return GenericDelegates<object, Task, T1, T2>.ThenWithArgs(task, successor, arg1, arg2) .FastUnwrap(); } } public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, Task<TResult>> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result).FastUnwrap(); default: return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result)) .FastUnwrap(); } } public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, TResult> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result); default: return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result)); } } public static Task<TResult> Then<T, T1, TResult>(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result, arg1); default: return GenericDelegates<T, TResult, T1, object>.ThenWithArgs(task, successor, arg1); } } public static Task Then(this Task task, Func<Task> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor).FastUnwrap(); default: return TaskRunners<object, Task>.RunTask(task, successor) .FastUnwrap(); } } public static Task<TResult> Then<TResult>(this Task task, Func<Task<TResult>> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor).FastUnwrap(); default: return TaskRunners<object, Task<TResult>>.RunTask(task, successor) .FastUnwrap(); } } public static Task Then<TResult>(this Task<TResult> task, Action<TResult> 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<TResult, object>.RunTask(task, successor); } } public static Task Then<TResult>(this Task<TResult> task, Func<TResult, Task> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result).FastUnwrap(); default: return TaskRunners<TResult, Task>.RunTask(task, t => successor(t.Result)) .FastUnwrap(); } } public static Task<TResult> Then<TResult, T1>(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task, arg1).FastUnwrap(); default: return GenericDelegates<TResult, Task<TResult>, T1, object>.ThenWithArgs(task, successor, arg1) .FastUnwrap(); } } public static Task FastUnwrap(this Task<Task> task) { var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; return innerTask ?? task.Unwrap(); } public static Task<T> FastUnwrap<T>(this Task<Task<T>> task) { var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; return innerTask ?? task.Unwrap(); } public static Task Delay(TimeSpan timeOut) { #if NETFX_CORE return Task.Delay(timeOut); #else var tcs = new TaskCompletionSource<object>(); var timer = new Timer(tcs.SetResult, null, timeOut, TimeSpan.FromMilliseconds(-1)); return tcs.Task.ContinueWith(_ => { timer.Dispose(); }, TaskContinuationOptions.ExecuteSynchronously); #endif } public static Task AllSucceeded(this Task[] tasks, Action continuation) { return AllSucceeded(tasks, _ => continuation()); } public static Task AllSucceeded(this Task[] tasks, Action<Task[]> continuation) { return Task.Factory.ContinueWhenAll(tasks, _ => { var cancelledTask = tasks.FirstOrDefault(task => task.IsCanceled); if (cancelledTask != null) throw new TaskCanceledException(); var allExceptions = tasks.Where(task => task.IsFaulted).SelectMany(task => task.Exception.InnerExceptions).ToList(); if (allExceptions.Count > 0) { throw new AggregateException(allExceptions); } continuation(tasks); }); } public static Task FromMethod(Action func) { try { func(); return Empty; } catch (Exception ex) { return FromError(ex); } } public static Task FromMethod<T1>(Action<T1> func, T1 arg) { try { func(arg); return Empty; } catch (Exception ex) { return FromError(ex); } } public static Task FromMethod<T1, T2>(Action<T1, T2> func, T1 arg1, T2 arg2) { try { func(arg1, arg2); return Empty; } catch (Exception ex) { return FromError(ex); } } public static Task<TResult> FromMethod<TResult>(Func<TResult> func) { try { return FromResult<TResult>(func()); } catch (Exception ex) { return FromError<TResult>(ex); } } public static Task<TResult> FromMethod<T1, TResult>(Func<T1, TResult> func, T1 arg) { try { return FromResult<TResult>(func(arg)); } catch (Exception ex) { return FromError<TResult>(ex); } } public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2) { try { return FromResult<TResult>(func(arg1, arg2)); } catch (Exception ex) { return FromError<TResult>(ex); } } public static Task<T> FromResult<T>(T value) { var tcs = new TaskCompletionSource<T>(); tcs.SetResult(value); return tcs.Task; } #if !NETFX_CORE public static TaskContinueWithMethod GetContinueWith(Type taskType) { var continueWith = (from m in taskType.GetMethods() let methodParameters = m.GetParameters() where m.Name.Equals("ContinueWith", StringComparison.OrdinalIgnoreCase) && methodParameters.Length == 1 let parameter = methodParameters[0] where parameter.ParameterType.IsGenericType && typeof(Func<,>) == parameter.ParameterType.GetGenericTypeDefinition() select new TaskContinueWithMethod { Method = m.MakeGenericMethod(typeof(Task)), Type = parameter.ParameterType.GetGenericArguments()[0] }) .FirstOrDefault(); return continueWith; } #endif internal static Task FromError(Exception e) { var tcs = new TaskCompletionSource<object>(); tcs.SetException(e); return tcs.Task; } internal static Task<T> FromError<T>(Exception e) { var tcs = new TaskCompletionSource<T>(); tcs.SetException(e); return tcs.Task; } private static Task Canceled() { var tcs = new TaskCompletionSource<object>(); tcs.SetCanceled(); return tcs.Task; } private static Task<T> Canceled<T>() { var tcs = new TaskCompletionSource<T>(); tcs.SetCanceled(); return tcs.Task; } public class TaskContinueWithMethod { public MethodInfo Method { get; set; } public Type Type { get; set; } } private static Task RunTask(Task task, Action successor) { var tcs = new TaskCompletionSource<object>(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { successor(); tcs.SetResult(null); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } private static class TaskRunners<T, TResult> { internal static Task RunTask(Task<T> task, Action<T> successor) { var tcs = new TaskCompletionSource<object>(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { successor(t.Result); tcs.SetResult(null); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } internal static Task<TResult> RunTask(Task task, Func<TResult> successor) { var tcs = new TaskCompletionSource<TResult>(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { tcs.SetResult(successor()); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } internal static Task<TResult> RunTask(Task<T> task, Func<Task<T>, TResult> successor) { var tcs = new TaskCompletionSource<TResult>(); task.ContinueWith(t => { if (task.IsFaulted) { tcs.SetException(t.Exception); } else if (task.IsCanceled) { tcs.SetCanceled(); } else { try { tcs.SetResult(successor(t)); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } } private static class GenericDelegates<T, TResult, T1, T2> { internal static Task ThenWithArgs(Task task, Action<T1> successor, T1 arg1) { return RunTask(task, () => successor(arg1)); } internal static Task ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2) { return RunTask(task, () => successor(arg1, arg2)); } internal static Task<TResult> ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1) { return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1)); } internal static Task<TResult> ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2) { return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1, arg2)); } internal static Task<TResult> ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1) { return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result, arg1)); } internal static Task<Task> ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1) { return TaskRunners<object, Task>.RunTask(task, () => successor(arg1)); } internal static Task<Task<TResult>> ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1) { return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result, arg1)); } internal static Task<Task<T>> ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1) { return TaskRunners<T, Task<T>>.RunTask(task, t => successor(t, arg1)); } } } } namespace Microshaoft { using System; using System.Threading.Tasks; using System.Web; public class HttpTaskAsyncHandler : IHttpAsyncHandler { public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { throw new NotSupportedException(); } public Task ProcessRequestAsync(HttpContextBase context) { // Microshaoft. //TaskAsyncHelper. return null; } IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { Task task = ProcessRequestAsync(new HttpContextWrapper(context)); var retVal = new TaskWrapperAsyncResult(task, extraData); if (task == null) { // No task, so just let ASP.NET deal with it return null; } if (cb != null) { // The callback needs the same argument that the Begin method returns, which is our special wrapper, not the original Task. task.ContinueWith(_ => cb(retVal)); } return retVal; } void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) { if (result == null) { throw new ArgumentNullException("result"); } // The End* method doesn't actually perform any actual work, but we do need to maintain two invariants: // 1. Make sure the underlying Task actually *is* complete. // 2. If the Task encountered an exception, observe it here. // (The Wait method handles both of those.) var castResult = (TaskWrapperAsyncResult)result; castResult.Task.Wait(); } } } namespace Microshaoft { using System; using System.Threading; using System.Threading.Tasks; internal sealed class TaskWrapperAsyncResult : IAsyncResult { internal TaskWrapperAsyncResult(Task task, object asyncState) { Task = task; AsyncState = asyncState; } public object AsyncState { get; private set; } public WaitHandle AsyncWaitHandle { get { return ((IAsyncResult)Task).AsyncWaitHandle; } } public bool CompletedSynchronously { get { return ((IAsyncResult)Task).CompletedSynchronously; } } public bool IsCompleted { get { return ((IAsyncResult)Task).IsCompleted; } } public Task Task { get; private set; } } } namespace Microshaoft { using System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; public static class TaskAsyncHelper { private static readonly Task _emptyTask = MakeEmpty(); private static Task MakeEmpty() { return FromResult<object>(null); } public static Task Empty { get { return _emptyTask; } } public static TTask Catch<TTask>(this TTask task) where TTask : Task { if (task != null && task.Status != TaskStatus.RanToCompletion) { task.ContinueWith(innerTask => { var ex = innerTask.Exception; // observe Exception #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE Trace.TraceError("SignalR exception thrown by Task: {0}", ex); #endif }, TaskContinuationOptions.OnlyOnFaulted); } return task; } public static TTask Catch<TTask>(this TTask task, Action<Exception> handler) where TTask : Task { if (task != null && task.Status != TaskStatus.RanToCompletion) { task.ContinueWith(innerTask => { var ex = innerTask.Exception; // observe Exception #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE Trace.TraceError("SignalR exception thrown by Task: {0}", ex); #endif handler(ex); }, TaskContinuationOptions.OnlyOnFaulted); } return task; } public static void ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } }, TaskContinuationOptions.NotOnRanToCompletion); } public static void ContinueWith(this Task task, TaskCompletionSource<object> tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.TrySetException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(null); } }); } public static void ContinueWith<T>(this Task<T> task, TaskCompletionSource<T> tcs) { task.ContinueWith(t => { if (t.IsFaulted) { tcs.TrySetException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(t.Result); } }); } /// <summary> /// Passes a task returning function into another task returning function so that /// it can decide when it starts and returns a task that completes when all are finished /// </summary> public static Task Interleave<T>(Func<T, Action, Task> before, Func<Task> after, T arg) { var tcs = new TaskCompletionSource<object>(); var tasks = new[] { tcs.Task, before(arg, () => after().ContinueWith(tcs)) }; return tasks.Return(); } public static Task Return(this Task[] tasks) { return Then(tasks, () => { }); } // Then extesions public static Task Then(this Task task, Action successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor); default: return RunTask(task, successor); } } public static Task<TResult> Then<TResult>(this Task task, Func<TResult> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor); default: return TaskRunners<object, TResult>.RunTask(task, successor); } } public static Task Then(this Task[] tasks, Action successor) { if (tasks.Length == 0) { return FromMethod(successor); } var tcs = new TaskCompletionSource<object>(); Task.Factory.ContinueWhenAll(tasks, completedTasks => { var faulted = completedTasks.FirstOrDefault(t => t.IsFaulted); if (faulted != null) { tcs.SetException(faulted.Exception); return; } var cancelled = completedTasks.FirstOrDefault(t => t.IsCanceled); if (cancelled != null) { tcs.SetCanceled(); return; } successor(); tcs.SetResult(null); }); return tcs.Task; } public static Task Then<T1>(this Task task, Action<T1> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1); default: return GenericDelegates<object, object, T1, object>.ThenWithArgs(task, successor, arg1); } } public static Task Then<T1, T2>(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1, arg2); default: return GenericDelegates<object, object, T1, T2>.ThenWithArgs(task, successor, arg1, arg2); } } public static Task Then<T1>(this Task task, Func<T1, Task> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1).FastUnwrap(); default: return GenericDelegates<object, Task, T1, object>.ThenWithArgs(task, successor, arg1) .FastUnwrap(); } } public static Task Then<T1, T2>(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, arg1, arg2).FastUnwrap(); default: return GenericDelegates<object, Task, T1, T2>.ThenWithArgs(task, successor, arg1, arg2) .FastUnwrap(); } } public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, Task<TResult>> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result).FastUnwrap(); default: return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result)) .FastUnwrap(); } } public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, TResult> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result); default: return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result)); } } public static Task<TResult> Then<T, T1, TResult>(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result, arg1); default: return GenericDelegates<T, TResult, T1, object>.ThenWithArgs(task, successor, arg1); } } public static Task Then(this Task task, Func<Task> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor).FastUnwrap(); default: return TaskRunners<object, Task>.RunTask(task, successor) .FastUnwrap(); } } public static Task<TResult> Then<TResult>(this Task task, Func<Task<TResult>> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor).FastUnwrap(); default: return TaskRunners<object, Task<TResult>>.RunTask(task, successor) .FastUnwrap(); } } public static Task Then<TResult>(this Task<TResult> task, Action<TResult> 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<TResult, object>.RunTask(task, successor); } } public static Task Then<TResult>(this Task<TResult> task, Func<TResult, Task> successor) { switch (task.Status) { case TaskStatus.Faulted: return FromError(task.Exception); case TaskStatus.Canceled: return Canceled(); case TaskStatus.RanToCompletion: return FromMethod(successor, task.Result).FastUnwrap(); default: return TaskRunners<TResult, Task>.RunTask(task, t => successor(t.Result)) .FastUnwrap(); } } public static Task<TResult> Then<TResult, T1>(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1) { switch (task.Status) { case TaskStatus.Faulted: return FromError<TResult>(task.Exception); case TaskStatus.Canceled: return Canceled<TResult>(); case TaskStatus.RanToCompletion: return FromMethod(successor, task, arg1).FastUnwrap(); default: return GenericDelegates<TResult, Task<TResult>, T1, object>.ThenWithArgs(task, successor, arg1) .FastUnwrap(); } } public static Task FastUnwrap(this Task<Task> task) { var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; return innerTask ?? task.Unwrap(); } public static Task<T> FastUnwrap<T>(this Task<Task<T>> task) { var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; return innerTask ?? task.Unwrap(); } public static Task Delay(TimeSpan timeOut) { #if NETFX_CORE return Task.Delay(timeOut); #else var tcs = new TaskCompletionSource<object>(); var timer = new Timer(tcs.SetResult, null, timeOut, TimeSpan.FromMilliseconds(-1)); return tcs.Task.ContinueWith(_ => { timer.Dispose(); }, TaskContinuationOptions.ExecuteSynchronously); #endif } public static Task AllSucceeded(this Task[] tasks, Action continuation) { return AllSucceeded(tasks, _ => continuation()); } public static Task AllSucceeded(this Task[] tasks, Action<Task[]> continuation) { return Task.Factory.ContinueWhenAll(tasks, _ => { var cancelledTask = tasks.FirstOrDefault(task => task.IsCanceled); if (cancelledTask != null) throw new TaskCanceledException(); var allExceptions = tasks.Where(task => task.IsFaulted).SelectMany(task => task.Exception.InnerExceptions).ToList(); if (allExceptions.Count > 0) { throw new AggregateException(allExceptions); } continuation(tasks); }); } public static Task FromMethod(Action func) { try { func(); return Empty; } catch (Exception ex) { return FromError(ex); } } public static Task FromMethod<T1>(Action<T1> func, T1 arg) { try { func(arg); return Empty; } catch (Exception ex) { return FromError(ex); } } public static Task FromMethod<T1, T2>(Action<T1, T2> func, T1 arg1, T2 arg2) { try { func(arg1, arg2); return Empty; } catch (Exception ex) { return FromError(ex); } } public static Task<TResult> FromMethod<TResult>(Func<TResult> func) { try { return FromResult<TResult>(func()); } catch (Exception ex) { return FromError<TResult>(ex); } } public static Task<TResult> FromMethod<T1, TResult>(Func<T1, TResult> func, T1 arg) { try { return FromResult<TResult>(func(arg)); } catch (Exception ex) { return FromError<TResult>(ex); } } public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2) { try { return FromResult<TResult>(func(arg1, arg2)); } catch (Exception ex) { return FromError<TResult>(ex); } } public static Task<T> FromResult<T>(T value) { var tcs = new TaskCompletionSource<T>(); tcs.SetResult(value); return tcs.Task; } #if !NETFX_CORE public static TaskContinueWithMethod GetContinueWith(Type taskType) { var continueWith = (from m in taskType.GetMethods() let methodParameters = m.GetParameters() where m.Name.Equals("ContinueWith", StringComparison.OrdinalIgnoreCase) && methodParameters.Length == 1 let parameter = methodParameters[0] where parameter.ParameterType.IsGenericType && typeof(Func<,>) == parameter.ParameterType.GetGenericTypeDefinition() select new TaskContinueWithMethod { Method = m.MakeGenericMethod(typeof(Task)), Type = parameter.ParameterType.GetGenericArguments()[0] }) .FirstOrDefault(); return continueWith; } #endif internal static Task FromError(Exception e) { var tcs = new TaskCompletionSource<object>(); tcs.SetException(e); return tcs.Task; } internal static Task<T> FromError<T>(Exception e) { var tcs = new TaskCompletionSource<T>(); tcs.SetException(e); return tcs.Task; } private static Task Canceled() { var tcs = new TaskCompletionSource<object>(); tcs.SetCanceled(); return tcs.Task; } private static Task<T> Canceled<T>() { var tcs = new TaskCompletionSource<T>(); tcs.SetCanceled(); return tcs.Task; } public class TaskContinueWithMethod { public MethodInfo Method { get; set; } public Type Type { get; set; } } private static Task RunTask(Task task, Action successor) { var tcs = new TaskCompletionSource<object>(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { successor(); tcs.SetResult(null); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } private static class TaskRunners<T, TResult> { internal static Task RunTask(Task<T> task, Action<T> successor) { var tcs = new TaskCompletionSource<object>(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { successor(t.Result); tcs.SetResult(null); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } internal static Task<TResult> RunTask(Task task, Func<TResult> successor) { var tcs = new TaskCompletionSource<TResult>(); task.ContinueWith(t => { if (t.IsFaulted) { tcs.SetException(t.Exception); } else if (t.IsCanceled) { tcs.SetCanceled(); } else { try { tcs.SetResult(successor()); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } internal static Task<TResult> RunTask(Task<T> task, Func<Task<T>, TResult> successor) { var tcs = new TaskCompletionSource<TResult>(); task.ContinueWith(t => { if (task.IsFaulted) { tcs.SetException(t.Exception); } else if (task.IsCanceled) { tcs.SetCanceled(); } else { try { tcs.SetResult(successor(t)); } catch (Exception ex) { tcs.SetException(ex); } } }); return tcs.Task; } } private static class GenericDelegates<T, TResult, T1, T2> { internal static Task ThenWithArgs(Task task, Action<T1> successor, T1 arg1) { return RunTask(task, () => successor(arg1)); } internal static Task ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2) { return RunTask(task, () => successor(arg1, arg2)); } internal static Task<TResult> ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1) { return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1)); } internal static Task<TResult> ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2) { return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1, arg2)); } internal static Task<TResult> ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1) { return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result, arg1)); } internal static Task<Task> ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1) { return TaskRunners<object, Task>.RunTask(task, () => successor(arg1)); } internal static Task<Task<TResult>> ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1) { return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result, arg1)); } internal static Task<Task<T>> ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1) { return TaskRunners<T, Task<T>>.RunTask(task, t => successor(t, arg1)); } } } } |