/// <summary> /// Run an asynchronous operation using the current thread as its synchronisation context. /// </summary> /// <typeparam name="TResult"> /// The operation result type. /// </typeparam> /// <param name="asyncOperation"> /// A <see cref="Func{TResult}" /> delegate representing the asynchronous operation to run. /// </param> /// <returns> /// The operation result. /// </returns> public static TResult RunSynchronized <TResult>(Func <Task <TResult> > asyncOperation) { if (asyncOperation == null) { throw new ArgumentNullException(nameof(asyncOperation)); } var savedContext = Current; try{ using (var synchronizationContext = new ThreadAffinitiveSynchronizationContext()){ SetSynchronizationContext(synchronizationContext); var rootOperationTask = asyncOperation(); if (rootOperationTask == null) { throw new InvalidOperationException("The asynchronous operation delegate cannot return null."); } rootOperationTask.ContinueWith( operationTask => // ReSharper disable once AccessToDisposedClosure synchronizationContext.TerminateMessagePump(), TaskScheduler.Default ); synchronizationContext.RunMessagePump(); try{ return (rootOperationTask .GetAwaiter() .GetResult()); } catch (AggregateException eWaitForTask ) // The TPL will almost always wrap an AggregateException around any exception thrown by the async operation. { // Is this just a wrapped exception? var flattenedAggregate = eWaitForTask.Flatten(); if (flattenedAggregate.InnerExceptions.Count != 1) { throw; // Nope, genuine aggregate. } // Yep, so rethrow (preserving original stack-trace). ExceptionDispatchInfo .Capture( flattenedAggregate .InnerExceptions[0] ) .Throw(); throw; // Never reached. } } } finally{ SetSynchronizationContext(savedContext); } }
/// <summary> /// Perform Cmdlet post-processing. /// </summary> protected sealed override void EndProcessing() { ThreadAffinitiveSynchronizationContext.RunSynchronized(EndProcessingAsync); }
/// <summary> /// Perform Cmdlet processing. /// </summary> protected sealed override void ProcessRecord() { ThreadAffinitiveSynchronizationContext.RunSynchronized(ProcessRecordAsync); }