That's because the implementation of ForEachAsync doesn't await the delegated action
moveNextTask = enumerator.MoveNextAsync(cancellationToken); action(current);
see https://github.com/mono/entityframework/blob/master/src/EntityFramework/Infrastructure/IDbAsyncEnumerableExtensions.cs#L19
But that is because, you can't await an action, the delegate needs to be a Func which returns a Task - see How do you implement an async action delegate method?
Therefore, until Microsoft provides a signature which includes a Func delegate and calls it with await, you'll have to roll your own extension method. I'm using the following at the moment.
public static async Task ForEachAsync<T>( this IQueryable<T> enumerable, Func<T, Task> action, CancellationToken cancellationToken) //Now with Func returning Task { var asyncEnumerable = (IDbAsyncEnumerable<T>)enumerable; using (var enumerator = asyncEnumerable.GetAsyncEnumerator()) { if (await enumerator.MoveNextAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)) { Task<bool> moveNextTask; do { var current = enumerator.Current; moveNextTask = enumerator.MoveNextAsync(cancellationToken); await action(current); //now with await } while (await moveNextTask.ConfigureAwait(continueOnCapturedContext: false)); } } }
With this, the original test code in your OP will work as expected.
foreach (var x in await qty.ToArrayAsync()) { ... }I guess?