AsyncDolls.AsyncDollsRecurseFree.Chain.Invoke C# (CSharp) Method

Invoke() public method

public Invoke ( IncomingContext context ) : Task
context IncomingContext
return Task
        public async Task Invoke(IncomingContext context)
        {
            int currentIndex = 0;
            var semaphore = new SemaphoreSlim(1);
            Stack<Tuple<Task, TaskCompletionSource<ExceptionDispatchInfo>>> sources = new Stack<Tuple<Task, TaskCompletionSource<ExceptionDispatchInfo>>>();

            while (currentIndex < executingElements.Count)
            {
                await semaphore.WaitAsync().ConfigureAwait(false);

                var element = executingElements[currentIndex];
                currentIndex += 1;

                var tcs = new TaskCompletionSource<ExceptionDispatchInfo>();
                var task = element.Invoke(context, () =>
                {
                    semaphore.Release();
                    return tcs.Task;
                });

                sources.Push(Tuple.Create(task, tcs));
            }

            ExceptionDispatchInfo exception = null;
            var anotherSemaphore = new SemaphoreSlim(1);
            var allTasks = new ConcurrentBag<Task>();
            foreach (var source in sources)
            {
                await anotherSemaphore.WaitAsync().ConfigureAwait(false);

                if (exception != null)
                {
                    context.Exceptions.Enqueue(exception);
                    source.Item2.TrySetException(exception.SourceException);
                    exception = null;
                }
                else
                {
                    source.Item2.TrySetResult(null);
                }

                var task = source.Item1.ContinueWith(t =>
                {
                    if (t.Exception != null)
                    {
                        exception = ExceptionDispatchInfo.Capture(t.Exception.InnerException);
                    }
                    anotherSemaphore.Release();
                }, TaskContinuationOptions.ExecuteSynchronously);
                allTasks.Add(task);
            }

            await Task.WhenAll(allTasks).ConfigureAwait(false);
        }
    }