3
votes

I have the following async method

private async Task<bool> HasPolicy(AuthorizationFilterContext context, string policy)
{
    var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
    return authorized.Succeeded;
}

I would like to use it in Enumerable.All and Enumerable.Any extension

var result1 = IsAndPolicy
    ? policys.All(async x => await HasPolicy(context, x))
    : policys.Any(async x => await HasPolicy(context, x));

But the above code gets the following error

Error CS4010 Cannot convert async lambda expression to delegate type 'Func<string, bool>'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func<string, bool>'.

2
Would you like to run these tasks concurrently or sequentially? - Theodor Zoulias
@TheodorZoulias, I think that in Any it should be sequentially and in All can be concurrently - roroinpho21

2 Answers

4
votes

One approach would be to project to an IEnumerable<Task<bool>>

var results = await Task.WhenAll(policys.Select(x => HasPolicy(context, x)));

var result1 = IsAndPolicy 
   ? results.All(x => x)                
   : results.Any(x => x);

The trouble with this approach, is you are processing all the items potentially needlessly.

2
votes

Michael Randall's answer produces the correct logical result but has to evaluate all policies, even though in both cases the evaluation can be short-circuited, by the first false result for All, or the first true result for Any.

This can be avoided by converting the tasks to an IAsyncenumerable<T> and using System.Linq.Async :

var resultTasks=policies.ToAsyncEnumerable()
                        .Select(async x => await HasPolicy(context, x));

var result1 = await (IsAndPolicy 
                       ? resultTasks.AllAsync(x => x)                
                       : resultTasks.AnyAsync(x => x));