Reputation: 550
I'm using c#, .net 6.0
I'm trying to convert IEnumerable method and ot's caller method to work asynchronously.
I have a code that looks something like that:
public IEnumerable<MyUser> getUsers()
{
return AccountById
.Keys
.SelectMany(accountId => {
try
{
return getUsersFor(accountId)
.Select(x => new MyUser(x,
SetAccountUniqueName(AccountById[accountId].Name,
AccountById[accountId].Id)));
}
catch (Exception ex)
{
_log.Error(ex);
return Enumerable.Empty<MyUser>();
}
});
}
public IEnumerable<User> getUsersFor(string accountId)
{
ListUsersResponse usersResponse;
string marker = null;
do
{
using (var myClient = new ServiceClient(accountId))
{
usersResponse =
myClient.ListUsersAsync(
new ListUsersRequest { Marker = marker, MaxItems = MAX_ITEMS })
.Result;
foreach (var user in usersResponse.Users)
{
yield return user;
}
}
marker = usersResponse.Marker;
} while (usersResponse.IsTruncated);
}
I converted getUsers() and getUsersFor() to work asynchronously.
I tried this code:
public async Task<List<MyUser>> GetUsersAsync()
{
return await AccountById
.Keys
.SelectMany(async accountId =>
{
try
{
await foreach (var user in GetUsersForAsync(accountId))
{
var u = new MyUser(user,
SetAccountUniqueName(AccountById[accountId].Name,
AccountById[accountId].Id));
return u;
}
}
catch (Exception ex)
{
_logger.Error(ex, $"Failed to get account {accountId} users list.");
return Enumerable.Empty<MyUser>();
}
});
}
public async IAsyncEnumerable<User> GetUsersForAsync(string accountId)
{
ListUsersResponse usersResponse;
string marker = null;
do
{
using (var myClient = new ServiceClient(accountId))
{
usersResponse =
await myClient.ListUsersAsync(
new ListUsersRequest { Marker = marker, MaxItems = MAX_ITEMS });
foreach (var user in usersResponse.Users)
{
yield return user;
}
}
marker = usersResponse.Marker;
} while (usersResponse.IsTruncated);
}
But I get this error:
The type arguments for method 'Enumerable.SelectMany<TSource, TResult>(IEnumerable, Func<TSource, IEnumerable>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Upvotes: 0
Views: 241
Reputation: 27528
You should not use LINQ for asynchronous operations. SelectMany of asynchronous call returns Task
which is wrong way if you do not await them.
Simple foreach
will work in your case, don't complicate things.
public async Task<List<MyUser>> GetUsersAsync()
{
var result = new List<MyUser>();
foreach (var accountId in AccountById.Keys)
{
try
{
await foreach (var user in GetUsersForAsync(accountId))
{
var u = new MyUser(user,
SetAccountUniqueName(AccountById[accountId].Name,
AccountById[accountId].Id));
result.Add(u);
}
}
catch (Exception ex)
{
_logger.Error(ex, $"Failed to get account {accountId} users list.");
}
}
return result;
}
Upvotes: 0