2

How can I set a Task.WhenAll() result to a value within a Task.WhenAll() routine? For example, the following code will get all authorized users for all domain/group combos in appRoleMaps:

var results = await Task.WhenAll(appRoleMaps.Select(
    x => GetAuthorizedUsers(x.DomainName, x.ADGroupName)));

But what if I want to set the authorized users results of each iteration as the iteration item Authorized property value? For example, something like the following code (although the following code does not work):

var results = await Task.WhenAll(appRoleMaps.Select(
    x => x.AuthorizedUsers = GetAuthorizedUsers(x.DomainName, x.ADGroupName)));

Is there a streamlined way to do this? Reason being, the GetAuthorizedUsers result set does not include domain/group info, so I can't just do a simple foreach/where at the end to easily join by this info.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
user9393635
  • 1,369
  • 4
  • 13
  • 32
  • Can you modify `GetAuthorizedUsers()` if so, have it create new objects that hold the domain and group name in them. – Ryan Wilson Jul 09 '18 at 20:37
  • yeah there are additional code structures and workarounds that I could implement but I was hoping for a more straightforward approach for setting this value within Task.WhenAll() which is the point of my original post – user9393635 Jul 09 '18 at 20:39
  • how does `WhenAll` apply here? does `appRoleMaps.Select` resolve to a list of tasks? – Cee McSharpface Jul 09 '18 at 20:39
  • @dlatikay I select authorized users based on the domainname/groupname for each appRoleMap via the Select – user9393635 Jul 09 '18 at 20:40
  • ah yes now I get it, with the assignment in the lambda it is no longer awaitable, so not valid for use with `WhenAll`. maybe try to make the lambda expression itself asynchronous? – Cee McSharpface Jul 09 '18 at 20:41
  • @dlatikay You mean like Douglas suggested in his answer a few minutes ago?? – Ryan Wilson Jul 09 '18 at 20:42

2 Answers2

4

You could create an async lambda to pass into your Select. This would cause each result to be assigned to the AuthorizedUsers property on the associated instance. The outer Task.WhenAll is only required to know when all elements have been processed.

await Task.WhenAll(appRoleMaps.Select(async x => 
    x.AuthorizedUsers = await GetAuthorizedUsers(x.DomainName, x.ADGroupName)));
Douglas
  • 53,759
  • 13
  • 140
  • 188
  • Looks like a good solution to me, once proven that this compiles and does what the OP is looking for I'll be happy to give you a +1 – Ryan Wilson Jul 09 '18 at 20:47
  • I tested it after I originally wrote it; it does compile. I remembered the pattern from [my answer for a similar problem](https://stackoverflow.com/a/23347895/1149773). – Douglas Jul 09 '18 at 20:49
  • Cool, +1 from me. Hopefully it solves the OP's problem but that is on them to pick an accepted answer. Thanks for this by the way, didn't realize you could do an async llambda. – Ryan Wilson Jul 09 '18 at 20:52
  • @RyanWilson: Here's a brief mention on MSDN: [Async Lambdas](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#async-lambdas). Their signature corresponds to a `Func<…,Task>` or `Func<…,Task>`, so they can be passed to methods that accept such as parameter. – Douglas Jul 09 '18 at 20:58
3

Save the tasks and query them after waiting:

var tasks = appRoleMaps.Select(x => GetAuthorizedUsers(x.DomainName, x.ADGroupName)).ToList();
await Task.WhenAll(tasks);
var results = tasks.Select(t => t.Result).ToList();

This is cleaner than relying on side effects. Squirreling the value away into some property and later extracting it obfuscates the meaning of the code and is more work to code.

usr
  • 168,620
  • 35
  • 240
  • 369