1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information. 2 3 using System; 4 using System.Collections; 5 using System.Collections.Generic; 6 using System.Diagnostics; 7 using System.Diagnostics.CodeAnalysis; 8 using System.Globalization; 9 using System.Linq; 10 using System.Reflection; 11 using System.Threading; 12 using System.Threading.Tasks; 13 using Microsoft.AspNet.SignalR.Infrastructure; 14 15 namespace Microsoft.AspNet.SignalR 16 { 17 internal static class TaskAsyncHelper 18 { 19 private static readonly Task _emptyTask = MakeTask<object>(null); 20 private static readonly Task<bool> _trueTask = MakeTask<bool>(true); 21 private static readonly Task<bool> _falseTask = MakeTask<bool>(false); 22 MakeTask(T value)23 private static Task<T> MakeTask<T>(T value) 24 { 25 return FromResult<T>(value); 26 } 27 28 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 29 public static Task Empty 30 { 31 get 32 { 33 return _emptyTask; 34 } 35 } 36 37 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 38 public static Task<bool> True 39 { 40 get 41 { 42 return _trueTask; 43 } 44 } 45 46 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 47 public static Task<bool> False 48 { 49 get 50 { 51 return _falseTask; 52 } 53 } 54 55 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] OrEmpty(this Task task)56 public static Task OrEmpty(this Task task) 57 { 58 return task ?? Empty; 59 } 60 61 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] OrEmpty(this Task<T> task)62 public static Task<T> OrEmpty<T>(this Task<T> task) 63 { 64 return task ?? TaskCache<T>.Empty; 65 } 66 67 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 68 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod, object state)69 public static Task FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod, object state) 70 { 71 try 72 { 73 return Task.Factory.FromAsync(beginMethod, endMethod, state); 74 } 75 catch (Exception ex) 76 { 77 return TaskAsyncHelper.FromError(ex); 78 } 79 } 80 81 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 82 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, T> endMethod, object state)83 public static Task<T> FromAsync<T>(Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, T> endMethod, object state) 84 { 85 try 86 { 87 return Task.Factory.FromAsync<T>(beginMethod, endMethod, state); 88 } 89 catch (Exception ex) 90 { 91 return TaskAsyncHelper.FromError<T>(ex); 92 } 93 } 94 95 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Series(Func<object, Task>[] tasks, object[] state)96 public static Task Series(Func<object, Task>[] tasks, object[] state) 97 { 98 Task prev = TaskAsyncHelper.Empty; 99 Task finalTask = TaskAsyncHelper.Empty; 100 101 for (int i = 0; i < tasks.Length; i++) 102 { 103 prev = finalTask; 104 finalTask = prev.Then(tasks[i], state[i]); 105 } 106 107 return finalTask; 108 } 109 110 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 111 public static TTask Catch<TTask>(this TTask task) where TTask : Task 112 { 113 return Catch(task, ex => { }); 114 } 115 116 #if PERFCOUNTERS 117 public static TTask Catch<TTask>(this TTask task, params IPerformanceCounter[] counters) where TTask : Task 118 { 119 return Catch(task, _ => 120 { 121 if (counters == null) 122 { 123 return; 124 } 125 for (var i = 0; i < counters.Length; i++) 126 { 127 counters[i].Increment(); 128 } 129 }); 130 } 131 #endif 132 133 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 134 public static TTask Catch<TTask>(this TTask task, Action<AggregateException, object> handler, object state) where TTask : Task 135 { 136 if (task != null && task.Status != TaskStatus.RanToCompletion) 137 { 138 if (task.Status == TaskStatus.Faulted) 139 { 140 ExecuteOnFaulted(handler, state, task.Exception); 141 } 142 else 143 { 144 AttachFaultedContinuation<TTask>(task, handler, state); 145 } 146 } 147 148 return task; 149 } 150 151 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 152 private static void AttachFaultedContinuation<TTask>(TTask task, Action<AggregateException, object> handler, object state) where TTask : Task 153 { 154 task.ContinueWith(innerTask => 155 { 156 ExecuteOnFaulted(handler, state, innerTask.Exception); 157 }, 158 TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); 159 } 160 161 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] ExecuteOnFaulted(Action<AggregateException, object> handler, object state, AggregateException exception)162 private static void ExecuteOnFaulted(Action<AggregateException, object> handler, object state, AggregateException exception) 163 { 164 // observe Exception 165 #if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE 166 Trace.TraceError("SignalR exception thrown by Task: {0}", exception); 167 #endif 168 handler(exception, state); 169 } 170 171 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 172 public static TTask Catch<TTask>(this TTask task, Action<AggregateException> handler) where TTask : Task 173 { 174 return task.Catch((ex, state) => ((Action<AggregateException>)state).Invoke(ex), 175 handler); 176 } 177 178 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 179 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] ContinueWithNotComplete(this Task task, Action action)180 public static Task ContinueWithNotComplete(this Task task, Action action) 181 { 182 switch (task.Status) 183 { 184 case TaskStatus.Faulted: 185 case TaskStatus.Canceled: 186 try 187 { 188 action(); 189 return task; 190 } 191 catch (Exception e) 192 { 193 return FromError(e); 194 } 195 case TaskStatus.RanToCompletion: 196 return task; 197 default: 198 var tcs = new TaskCompletionSource<object>(); 199 200 task.ContinueWith(t => 201 { 202 if (t.IsFaulted || t.IsCanceled) 203 { 204 try 205 { 206 action(); 207 208 if (t.IsFaulted) 209 { 210 tcs.TrySetUnwrappedException(t.Exception); 211 } 212 else 213 { 214 tcs.TrySetCanceled(); 215 } 216 } 217 catch (Exception e) 218 { 219 tcs.TrySetException(e); 220 } 221 } 222 else 223 { 224 tcs.TrySetResult(null); 225 } 226 }, 227 TaskContinuationOptions.ExecuteSynchronously); 228 229 return tcs.Task; 230 } 231 } 232 233 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs)234 public static void ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs) 235 { 236 task.ContinueWith(t => 237 { 238 if (t.IsFaulted) 239 { 240 tcs.SetUnwrappedException(t.Exception); 241 } 242 else if (t.IsCanceled) 243 { 244 tcs.SetCanceled(); 245 } 246 }, 247 TaskContinuationOptions.NotOnRanToCompletion); 248 } 249 250 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] ContinueWith(this Task task, TaskCompletionSource<object> tcs)251 public static void ContinueWith(this Task task, TaskCompletionSource<object> tcs) 252 { 253 task.ContinueWith(t => 254 { 255 if (t.IsFaulted) 256 { 257 tcs.TrySetUnwrappedException(t.Exception); 258 } 259 else if (t.IsCanceled) 260 { 261 tcs.TrySetCanceled(); 262 } 263 else 264 { 265 tcs.TrySetResult(null); 266 } 267 }, 268 TaskContinuationOptions.ExecuteSynchronously); 269 } 270 271 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] ContinueWith(this Task<T> task, TaskCompletionSource<T> tcs)272 public static void ContinueWith<T>(this Task<T> task, TaskCompletionSource<T> tcs) 273 { 274 task.ContinueWith(t => 275 { 276 if (t.IsFaulted) 277 { 278 tcs.TrySetUnwrappedException(t.Exception); 279 } 280 else if (t.IsCanceled) 281 { 282 tcs.TrySetCanceled(); 283 } 284 else 285 { 286 tcs.TrySetResult(t.Result); 287 } 288 }); 289 } 290 291 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Return(this Task[] tasks)292 public static Task Return(this Task[] tasks) 293 { 294 return Then(tasks, () => { }); 295 } 296 297 // Then extesions 298 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Action successor)299 public static Task Then(this Task task, Action successor) 300 { 301 switch (task.Status) 302 { 303 case TaskStatus.Faulted: 304 case TaskStatus.Canceled: 305 return task; 306 307 case TaskStatus.RanToCompletion: 308 return FromMethod(successor); 309 310 default: 311 return RunTask(task, successor); 312 } 313 } 314 315 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Func<TResult> successor)316 public static Task<TResult> Then<TResult>(this Task task, Func<TResult> successor) 317 { 318 switch (task.Status) 319 { 320 case TaskStatus.Faulted: 321 return FromError<TResult>(task.Exception); 322 323 case TaskStatus.Canceled: 324 return Canceled<TResult>(); 325 326 case TaskStatus.RanToCompletion: 327 return FromMethod(successor); 328 329 default: 330 return TaskRunners<object, TResult>.RunTask(task, successor); 331 } 332 } 333 334 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task[] tasks, Action successor)335 public static Task Then(this Task[] tasks, Action successor) 336 { 337 if (tasks.Length == 0) 338 { 339 return FromMethod(successor); 340 } 341 342 var tcs = new TaskCompletionSource<object>(); 343 Task.Factory.ContinueWhenAll(tasks, completedTasks => 344 { 345 var faulted = completedTasks.FirstOrDefault(t => t.IsFaulted); 346 if (faulted != null) 347 { 348 tcs.SetUnwrappedException(faulted.Exception); 349 return; 350 } 351 var cancelled = completedTasks.FirstOrDefault(t => t.IsCanceled); 352 if (cancelled != null) 353 { 354 tcs.SetCanceled(); 355 return; 356 } 357 358 successor(); 359 tcs.SetResult(null); 360 }); 361 362 return tcs.Task; 363 } 364 365 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Action<T1> successor, T1 arg1)366 public static Task Then<T1>(this Task task, Action<T1> successor, T1 arg1) 367 { 368 switch (task.Status) 369 { 370 case TaskStatus.Faulted: 371 case TaskStatus.Canceled: 372 return task; 373 374 case TaskStatus.RanToCompletion: 375 return FromMethod(successor, arg1); 376 377 default: 378 return GenericDelegates<object, object, T1, object>.ThenWithArgs(task, successor, arg1); 379 } 380 } 381 382 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)383 public static Task Then<T1, T2>(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2) 384 { 385 switch (task.Status) 386 { 387 case TaskStatus.Faulted: 388 case TaskStatus.Canceled: 389 return task; 390 391 case TaskStatus.RanToCompletion: 392 return FromMethod(successor, arg1, arg2); 393 394 default: 395 return GenericDelegates<object, object, T1, T2>.ThenWithArgs(task, successor, arg1, arg2); 396 } 397 } 398 399 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Func<T1, Task> successor, T1 arg1)400 public static Task Then<T1>(this Task task, Func<T1, Task> successor, T1 arg1) 401 { 402 switch (task.Status) 403 { 404 case TaskStatus.Faulted: 405 case TaskStatus.Canceled: 406 return task; 407 408 case TaskStatus.RanToCompletion: 409 return FromMethod(successor, arg1); 410 411 default: 412 return GenericDelegates<object, Task, T1, object>.ThenWithArgs(task, successor, arg1) 413 .FastUnwrap(); 414 } 415 } 416 417 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)418 public static Task Then<T1, T2>(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2) 419 { 420 switch (task.Status) 421 { 422 case TaskStatus.Faulted: 423 case TaskStatus.Canceled: 424 return task; 425 426 case TaskStatus.RanToCompletion: 427 return FromMethod(successor, arg1, arg2); 428 429 default: 430 return GenericDelegates<object, Task, T1, T2>.ThenWithArgs(task, successor, arg1, arg2) 431 .FastUnwrap(); 432 } 433 } 434 435 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task<T> task, Func<T, Task<TResult>> successor)436 public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, Task<TResult>> successor) 437 { 438 switch (task.Status) 439 { 440 case TaskStatus.Faulted: 441 return FromError<TResult>(task.Exception); 442 443 case TaskStatus.Canceled: 444 return Canceled<TResult>(); 445 446 case TaskStatus.RanToCompletion: 447 return FromMethod(successor, task.Result); 448 449 default: 450 return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result)) 451 .FastUnwrap(); 452 } 453 } 454 455 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task<T> task, Func<T, TResult> successor)456 public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, TResult> successor) 457 { 458 switch (task.Status) 459 { 460 case TaskStatus.Faulted: 461 return FromError<TResult>(task.Exception); 462 463 case TaskStatus.Canceled: 464 return Canceled<TResult>(); 465 466 case TaskStatus.RanToCompletion: 467 return FromMethod(successor, task.Result); 468 469 default: 470 return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result)); 471 } 472 } 473 474 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1)475 public static Task<TResult> Then<T, T1, TResult>(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1) 476 { 477 switch (task.Status) 478 { 479 case TaskStatus.Faulted: 480 return FromError<TResult>(task.Exception); 481 482 case TaskStatus.Canceled: 483 return Canceled<TResult>(); 484 485 case TaskStatus.RanToCompletion: 486 return FromMethod(successor, task.Result, arg1); 487 488 default: 489 return GenericDelegates<T, TResult, T1, object>.ThenWithArgs(task, successor, arg1); 490 } 491 } 492 493 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Func<Task> successor)494 public static Task Then(this Task task, Func<Task> successor) 495 { 496 switch (task.Status) 497 { 498 case TaskStatus.Faulted: 499 case TaskStatus.Canceled: 500 return task; 501 502 case TaskStatus.RanToCompletion: 503 return FromMethod(successor); 504 505 default: 506 return TaskRunners<object, Task>.RunTask(task, successor) 507 .FastUnwrap(); 508 } 509 } 510 511 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task task, Func<Task<TResult>> successor)512 public static Task<TResult> Then<TResult>(this Task task, Func<Task<TResult>> successor) 513 { 514 switch (task.Status) 515 { 516 case TaskStatus.Faulted: 517 return FromError<TResult>(task.Exception); 518 519 case TaskStatus.Canceled: 520 return Canceled<TResult>(); 521 522 case TaskStatus.RanToCompletion: 523 return FromMethod(successor); 524 525 default: 526 return TaskRunners<object, Task<TResult>>.RunTask(task, successor) 527 .FastUnwrap(); 528 } 529 } 530 531 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task<TResult> task, Action<TResult> successor)532 public static Task Then<TResult>(this Task<TResult> task, Action<TResult> successor) 533 { 534 switch (task.Status) 535 { 536 case TaskStatus.Faulted: 537 case TaskStatus.Canceled: 538 return task; 539 540 case TaskStatus.RanToCompletion: 541 return FromMethod(successor, task.Result); 542 543 default: 544 return TaskRunners<TResult, object>.RunTask(task, successor); 545 } 546 } 547 548 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task<TResult> task, Func<TResult, Task> successor)549 public static Task Then<TResult>(this Task<TResult> task, Func<TResult, Task> successor) 550 { 551 switch (task.Status) 552 { 553 case TaskStatus.Faulted: 554 case TaskStatus.Canceled: 555 return task; 556 557 case TaskStatus.RanToCompletion: 558 return FromMethod(successor, task.Result); 559 560 default: 561 return TaskRunners<TResult, Task>.RunTask(task, t => successor(t.Result)) 562 .FastUnwrap(); 563 } 564 } 565 566 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Then(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1)567 public static Task<TResult> Then<TResult, T1>(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1) 568 { 569 switch (task.Status) 570 { 571 case TaskStatus.Faulted: 572 case TaskStatus.Canceled: 573 return task; 574 575 case TaskStatus.RanToCompletion: 576 return FromMethod(successor, task, arg1); 577 578 default: 579 return GenericDelegates<TResult, Task<TResult>, T1, object>.ThenWithArgs(task, successor, arg1) 580 .FastUnwrap(); 581 } 582 } 583 584 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are flowed to the caller")] 585 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Finally(this Task task, Action<object> next, object state)586 public static Task Finally(this Task task, Action<object> next, object state) 587 { 588 try 589 { 590 switch (task.Status) 591 { 592 case TaskStatus.Faulted: 593 case TaskStatus.Canceled: 594 next(state); 595 return task; 596 case TaskStatus.RanToCompletion: 597 return FromMethod(next, state); 598 599 default: 600 return RunTaskSynchronously(task, next, state, onlyOnSuccess: false); 601 } 602 } 603 catch (Exception ex) 604 { 605 return FromError(ex); 606 } 607 } 608 609 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] RunSynchronously(this Task task, Action successor)610 public static Task RunSynchronously(this Task task, Action successor) 611 { 612 switch (task.Status) 613 { 614 case TaskStatus.Faulted: 615 case TaskStatus.Canceled: 616 return task; 617 618 case TaskStatus.RanToCompletion: 619 return FromMethod(successor); 620 621 default: 622 return RunTaskSynchronously(task, state => ((Action)state).Invoke(), successor); 623 } 624 } 625 626 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] FastUnwrap(this Task<Task> task)627 public static Task FastUnwrap(this Task<Task> task) 628 { 629 var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; 630 return innerTask ?? task.Unwrap(); 631 } 632 633 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] FastUnwrap(this Task<Task<T>> task)634 public static Task<T> FastUnwrap<T>(this Task<Task<T>> task) 635 { 636 var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null; 637 return innerTask ?? task.Unwrap(); 638 } 639 640 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Delay(TimeSpan timeOut)641 public static Task Delay(TimeSpan timeOut) 642 { 643 #if NETFX_CORE 644 return Task.Delay(timeOut); 645 #else 646 var tcs = new TaskCompletionSource<object>(); 647 648 var timer = new Timer(tcs.SetResult, 649 null, 650 timeOut, 651 TimeSpan.FromMilliseconds(-1)); 652 653 return tcs.Task.ContinueWith(_ => 654 { 655 timer.Dispose(); 656 }, 657 TaskContinuationOptions.ExecuteSynchronously); 658 #endif 659 } 660 661 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 662 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Action func)663 public static Task FromMethod(Action func) 664 { 665 try 666 { 667 func(); 668 return Empty; 669 } 670 catch (Exception ex) 671 { 672 return FromError(ex); 673 } 674 } 675 676 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 677 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Action<T1> func, T1 arg)678 public static Task FromMethod<T1>(Action<T1> func, T1 arg) 679 { 680 try 681 { 682 func(arg); 683 return Empty; 684 } 685 catch (Exception ex) 686 { 687 return FromError(ex); 688 } 689 } 690 691 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 692 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Action<T1, T2> func, T1 arg1, T2 arg2)693 public static Task FromMethod<T1, T2>(Action<T1, T2> func, T1 arg1, T2 arg2) 694 { 695 try 696 { 697 func(arg1, arg2); 698 return Empty; 699 } 700 catch (Exception ex) 701 { 702 return FromError(ex); 703 } 704 } 705 706 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 707 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<Task> func)708 public static Task FromMethod(Func<Task> func) 709 { 710 try 711 { 712 return func(); 713 } 714 catch (Exception ex) 715 { 716 return FromError(ex); 717 } 718 } 719 720 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 721 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<Task<TResult>> func)722 public static Task<TResult> FromMethod<TResult>(Func<Task<TResult>> func) 723 { 724 try 725 { 726 return func(); 727 } 728 catch (Exception ex) 729 { 730 return FromError<TResult>(ex); 731 } 732 } 733 734 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 735 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<TResult> func)736 public static Task<TResult> FromMethod<TResult>(Func<TResult> func) 737 { 738 try 739 { 740 return FromResult<TResult>(func()); 741 } 742 catch (Exception ex) 743 { 744 return FromError<TResult>(ex); 745 } 746 } 747 748 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 749 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<T1, Task> func, T1 arg)750 public static Task FromMethod<T1>(Func<T1, Task> func, T1 arg) 751 { 752 try 753 { 754 return func(arg); 755 } 756 catch (Exception ex) 757 { 758 return FromError(ex); 759 } 760 } 761 762 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 763 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<T1, T2, Task> func, T1 arg1, T2 arg2)764 public static Task FromMethod<T1, T2>(Func<T1, T2, Task> func, T1 arg1, T2 arg2) 765 { 766 try 767 { 768 return func(arg1, arg2); 769 } 770 catch (Exception ex) 771 { 772 return FromError(ex); 773 } 774 } 775 776 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 777 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<T1, Task<TResult>> func, T1 arg)778 public static Task<TResult> FromMethod<T1, TResult>(Func<T1, Task<TResult>> func, T1 arg) 779 { 780 try 781 { 782 return func(arg); 783 } 784 catch (Exception ex) 785 { 786 return FromError<TResult>(ex); 787 } 788 } 789 790 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 791 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<T1, TResult> func, T1 arg)792 public static Task<TResult> FromMethod<T1, TResult>(Func<T1, TResult> func, T1 arg) 793 { 794 try 795 { 796 return FromResult<TResult>(func(arg)); 797 } 798 catch (Exception ex) 799 { 800 return FromError<TResult>(ex); 801 } 802 } 803 804 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 805 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<T1, T2, Task<TResult>> func, T1 arg1, T2 arg2)806 public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, Task<TResult>> func, T1 arg1, T2 arg2) 807 { 808 try 809 { 810 return func(arg1, arg2); 811 } 812 catch (Exception ex) 813 { 814 return FromError<TResult>(ex); 815 } 816 } 817 818 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] 819 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] FromMethod(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)820 public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2) 821 { 822 try 823 { 824 return FromResult<TResult>(func(arg1, arg2)); 825 } 826 catch (Exception ex) 827 { 828 return FromError<TResult>(ex); 829 } 830 } 831 832 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] FromResult(T value)833 public static Task<T> FromResult<T>(T value) 834 { 835 var tcs = new TaskCompletionSource<T>(); 836 tcs.SetResult(value); 837 return tcs.Task; 838 } 839 840 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] FromError(Exception e)841 internal static Task FromError(Exception e) 842 { 843 return FromError<object>(e); 844 } 845 846 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] FromError(Exception e)847 internal static Task<T> FromError<T>(Exception e) 848 { 849 var tcs = new TaskCompletionSource<T>(); 850 tcs.SetUnwrappedException<T>(e); 851 return tcs.Task; 852 } 853 854 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] SetUnwrappedException(this TaskCompletionSource<T> tcs, Exception e)855 internal static void SetUnwrappedException<T>(this TaskCompletionSource<T> tcs, Exception e) 856 { 857 var aggregateException = e as AggregateException; 858 if (aggregateException != null) 859 { 860 tcs.SetException(aggregateException.InnerExceptions); 861 } 862 else 863 { 864 tcs.SetException(e); 865 } 866 } 867 868 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] TrySetUnwrappedException(this TaskCompletionSource<T> tcs, Exception e)869 internal static bool TrySetUnwrappedException<T>(this TaskCompletionSource<T> tcs, Exception e) 870 { 871 var aggregateException = e as AggregateException; 872 if (aggregateException != null) 873 { 874 return tcs.TrySetException(aggregateException.InnerExceptions); 875 } 876 else 877 { 878 return tcs.TrySetException(e); 879 } 880 } 881 882 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Canceled()883 private static Task Canceled() 884 { 885 var tcs = new TaskCompletionSource<object>(); 886 tcs.SetCanceled(); 887 return tcs.Task; 888 } 889 890 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] Canceled()891 private static Task<T> Canceled<T>() 892 { 893 var tcs = new TaskCompletionSource<T>(); 894 tcs.SetCanceled(); 895 return tcs.Task; 896 } 897 898 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] RunTask(Task task, Action successor)899 private static Task RunTask(Task task, Action successor) 900 { 901 var tcs = new TaskCompletionSource<object>(); 902 task.ContinueWith(t => 903 { 904 if (t.IsFaulted) 905 { 906 tcs.SetUnwrappedException(t.Exception); 907 } 908 else if (t.IsCanceled) 909 { 910 tcs.SetCanceled(); 911 } 912 else 913 { 914 try 915 { 916 successor(); 917 tcs.SetResult(null); 918 } 919 catch (Exception ex) 920 { 921 tcs.SetUnwrappedException(ex); 922 } 923 } 924 }); 925 926 return tcs.Task; 927 } 928 929 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] 930 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")] RunTaskSynchronously(Task task, Action<object> next, object state, bool onlyOnSuccess = true)931 private static Task RunTaskSynchronously(Task task, Action<object> next, object state, bool onlyOnSuccess = true) 932 { 933 var tcs = new TaskCompletionSource<object>(); 934 task.ContinueWith(t => 935 { 936 try 937 { 938 if (t.IsFaulted) 939 { 940 if (!onlyOnSuccess) 941 { 942 next(state); 943 } 944 945 tcs.SetUnwrappedException(t.Exception); 946 } 947 else if (t.IsCanceled) 948 { 949 if (!onlyOnSuccess) 950 { 951 next(state); 952 } 953 954 tcs.SetCanceled(); 955 } 956 else 957 { 958 next(state); 959 tcs.SetResult(null); 960 } 961 } 962 catch (Exception ex) 963 { 964 tcs.SetUnwrappedException(ex); 965 } 966 }, 967 TaskContinuationOptions.ExecuteSynchronously); 968 969 return tcs.Task; 970 } 971 972 private static class TaskRunners<T, TResult> 973 { 974 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] RunTask(Task<T> task, Action<T> successor)975 internal static Task RunTask(Task<T> task, Action<T> successor) 976 { 977 var tcs = new TaskCompletionSource<object>(); 978 task.ContinueWith(t => 979 { 980 if (t.IsFaulted) 981 { 982 tcs.SetUnwrappedException(t.Exception); 983 } 984 else if (t.IsCanceled) 985 { 986 tcs.SetCanceled(); 987 } 988 else 989 { 990 try 991 { 992 successor(t.Result); 993 tcs.SetResult(null); 994 } 995 catch (Exception ex) 996 { 997 tcs.SetUnwrappedException(ex); 998 } 999 } 1000 }); 1001 1002 return tcs.Task; 1003 } 1004 1005 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] RunTask(Task task, Func<TResult> successor)1006 internal static Task<TResult> RunTask(Task task, Func<TResult> successor) 1007 { 1008 var tcs = new TaskCompletionSource<TResult>(); 1009 task.ContinueWith(t => 1010 { 1011 if (t.IsFaulted) 1012 { 1013 tcs.SetUnwrappedException(t.Exception); 1014 } 1015 else if (t.IsCanceled) 1016 { 1017 tcs.SetCanceled(); 1018 } 1019 else 1020 { 1021 try 1022 { 1023 tcs.SetResult(successor()); 1024 } 1025 catch (Exception ex) 1026 { 1027 tcs.SetUnwrappedException(ex); 1028 } 1029 } 1030 }); 1031 1032 return tcs.Task; 1033 } 1034 1035 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")] RunTask(Task<T> task, Func<Task<T>, TResult> successor)1036 internal static Task<TResult> RunTask(Task<T> task, Func<Task<T>, TResult> successor) 1037 { 1038 var tcs = new TaskCompletionSource<TResult>(); 1039 task.ContinueWith(t => 1040 { 1041 if (task.IsFaulted) 1042 { 1043 tcs.SetUnwrappedException(t.Exception); 1044 } 1045 else if (task.IsCanceled) 1046 { 1047 tcs.SetCanceled(); 1048 } 1049 else 1050 { 1051 try 1052 { 1053 tcs.SetResult(successor(t)); 1054 } 1055 catch (Exception ex) 1056 { 1057 tcs.SetUnwrappedException(ex); 1058 } 1059 } 1060 }); 1061 1062 return tcs.Task; 1063 } 1064 } 1065 1066 private static class GenericDelegates<T, TResult, T1, T2> 1067 { ThenWithArgs(Task task, Action<T1> successor, T1 arg1)1068 internal static Task ThenWithArgs(Task task, Action<T1> successor, T1 arg1) 1069 { 1070 return RunTask(task, () => successor(arg1)); 1071 } 1072 ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)1073 internal static Task ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2) 1074 { 1075 return RunTask(task, () => successor(arg1, arg2)); 1076 } 1077 ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1)1078 internal static Task<TResult> ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1) 1079 { 1080 return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1)); 1081 } 1082 ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2)1083 internal static Task<TResult> ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2) 1084 { 1085 return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1, arg2)); 1086 } 1087 ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1)1088 internal static Task<TResult> ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1) 1089 { 1090 return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result, arg1)); 1091 } 1092 ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1)1093 internal static Task<Task> ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1) 1094 { 1095 return TaskRunners<object, Task>.RunTask(task, () => successor(arg1)); 1096 } 1097 ThenWithArgs(Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)1098 internal static Task<Task> ThenWithArgs(Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2) 1099 { 1100 return TaskRunners<object, Task>.RunTask(task, () => successor(arg1, arg2)); 1101 } 1102 ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1)1103 internal static Task<Task<TResult>> ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1) 1104 { 1105 return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result, arg1)); 1106 } 1107 ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1)1108 internal static Task<Task<T>> ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1) 1109 { 1110 return TaskRunners<T, Task<T>>.RunTask(task, t => successor(t, arg1)); 1111 } 1112 } 1113 1114 private static class TaskCache<T> 1115 { 1116 public static Task<T> Empty = MakeTask<T>(default(T)); 1117 } 1118 } 1119 } 1120