Dasync/AsyncEnumerable

Enumerators are not automatically Enumerated during WebAPI serialization.

Closed this issue · 2 comments

Consider the following WebAPI code:

// GET api/values
public IEnumerable<string> Get()
{
    for (int i = 0; i < 5; i++)
    {
        yield return "Value" + i;
    }
}

When the URL is called from a browser you get:

[
  "Value0",
  "Value1",
  "Value2",
  "Value3",
  "Value4"
]

Using the equivalent IAsyncEnumerable code does not work the same:

// GET api/values
public IAsyncEnumerable<string> Get()
{
    return new AsyncEnumerable<string>
    (
        async yield =>
        {
            for (int i = 0; i < 5; i++)
            {
                await yield.ReturnAsync("Value" + i);
            }
        }
    );
}

When the URL is called from a browser you get:

{}

On a side note -- would it be easier if we could convert it to an IQueryable? -- (i.e. you could implement the OData REST queries as async, etc.)

Hi @BrainSlugs83, unfortunately this is an expected behavior, because WebAPI (or any other consumer of IAsyncEnumerable) does not really know that there is a collection behind this object, so the JSON serializer just tries to pull fields from the AsyncEnumerable object.

The problem with IQueryable is that it does not support any asynchronous enumeration, that's why there projects like Rx/Lx exist. Another example, Entity Framework has it's own async extensions to IQueryable, but they are EF-specific only. The point being, there is no standard interface that allows you to do an enumeration in asynchronous manner, but hopefully it will come in the future versions of the .NET Framework/Standard.

One thing you could do is to read the collection into memory using '.ToListAsync()' extension method:

// GET api/values
public async Task<IEnumerable<string>> Get()
{
    var asyncEnumerable = new AsyncEnumerable<string>
    (
        async yield =>
        {
            for (int i = 0; i < 5; i++)
            {
                await yield.ReturnAsync("Value" + i);
            }
        }
    );
    return await asyncEnumerable.ToListAsync();
}