Feature request: Enable usage of `IAsyncEnumerable<T>` for e. g. `ResourceSet<Room>`
Eagle3386 opened this issue · 2 comments
Eagle3386 commented
Issue Summary
Besides PR #589 which remains open for about half a year now, I'd like to ask for enhancement to the Video API so that I could do this:
Steps to Reproduce
- Implement a method that queries the Video API for available rooms like below.
- Try to consume that method or at least make the compiler accept that method's content.
Code Snippet
// [... code left out for brevity ...]
using static Twilio.Rest.Video.V1.Room.ParticipantResource;
using static Twilio.Rest.Video.V1.RoomResource;
// [... code left out for brevity ...]
public class TwilioService
{
// [... code left out for brevity ...]
public async IAsyncEnumerable<Room> GetRoomsAsync()
{
var roomTasks = (await ReadAsync().ConfigureAwait(false)).Select(room => Task.Run(async () => new Room
{
Name = room.UniqueName,
ParticipantCount = (await ReadAsync(room.Sid, StatusEnum.Connected).ConfigureAwait(false)).Count(),
ParticipantLimit = room.MaxParticipants ?? 0
}));
await foreach (var room in roomTasks.ConfigureAwait(false))
{
yield return room;
}
}
}
// [... code left out for brevity ...]
public class Room
{
public string Id { get; init; } = null!;
public string Name { get; init; } = null!;
public int ParticipantCount { get; set; }
public int ParticipantLimit { get; init; }
}
Exception/Log
Error Code: CS8415
Description: Asynchronous foreach statement cannot operate on variables of type 'IEnumerable<Task<Room>>' because
'IEnumerable<Task<Room>>' does not contain a public instance or extension definition for
'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'await foreach'?
Technical details:
- twilio-csharp version: 5.75.0
- csharp version: 10 (.NET 6)
childish-sambino commented
This issue has been added to our internal backlog to be prioritized. Pull requests and +1s on the issue summary will help it move up the backlog.
Eagle3386 commented
FWIW: using NuGet package System.Linq.Async
, the initial code snippet can be simplified to this:
public async IAsyncEnumerable<Room> GetRoomsAsync([EnumeratorCancellation] CancellationToken token = default)
{
var rooms = await RoomResource.ReadAsync().ConfigureAwait(false);
await foreach (var room in rooms.ToAsyncEnumerable().WithCancellation(token).ConfigureAwait(false))
{
var participants = await ParticipantResource.ReadAsync(room.Sid, StatusEnum.Connected).ConfigureAwait(false);
yield return new Room
{
Name = room.UniqueName,
ParticipantCount = participants.Count(),
ParticipantLimit = room.MaxParticipants ?? 0
};
}
}
Furthermore, I'd like to suggest that the Room
type exposes an additional int
property like CurrentParticipants
, thereby delivering 2 advantages at once:
- Enable immediate discovery of already active participants within the room (
CurrentParticipants
> 0). - Prevent 1 additionally (
await
ed) round-trip toParticipantResource.ReadAsync()
.