/// <summary> /// Synchronously executes a cancelable async task with a void return value. /// If the current thread is being aborted or interrupted then a corresponding cancellation request is issued for the given task. /// </summary> /// <param name="task">The cancelable async task to execute.</param> public static void Execute(Func <CancellationToken, Task> task) { if (task == null) { throw new ArgumentNullException(nameof(task)); } try { var savedContext = SynchronizationContext.Current; using (var cts = new CancellationTokenSource()) { Task pendingTask = null; var context = new ExclusiveSynchronizationContext(); try { SynchronizationContext.SetSynchronizationContext(context); context.Execute(() => pendingTask = task(cts.Token)); pendingTask = null; } catch (Exception ex) when(ex is ThreadAbortException || ex is ThreadInterruptedException) { cts.Cancel(); if (pendingTask != null) { context.ExceptionFilter = exception => !(exception is TaskCanceledException); // Execute remaining async iterations and finalizers. context.Execute(() => pendingTask); } throw; } finally { SynchronizationContext.SetSynchronizationContext(savedContext); } } } catch (AggregateException e) when(e.InnerExceptions.Count == 1) { throw e.InnerExceptions[0]; } }
/// <summary> /// Synchronously executes an async task with a void return value. /// </summary> /// <param name="task">The async task to execute.</param> public static void Execute(Func <Task> task) { if (task == null) { throw new ArgumentNullException(nameof(task)); } var savedContext = SynchronizationContext.Current; var context = new ExclusiveSynchronizationContext(); try { SynchronizationContext.SetSynchronizationContext(context); context.Execute(task); } finally { SynchronizationContext.SetSynchronizationContext(savedContext); } }