Clarification sur la façon dont IAsyncEnumerable fonctionne avec l'API Web ASP.NET

9

J'ai rencontré un comportement intéressant lors de l'exploration d'IAsyncEnumerable dans un projet d'API Web ASP.NET. Considérez les exemples de code suivants:

    // Code Sample 1
    [HttpGet]
    public async IAsyncEnumerable<int> GetAsync()
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            yield return i;
        }
    }


    // Code Sample 2
    [HttpGet]
    public async IAsyncEnumerable<string> GetAsync()
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            yield return i.ToString();
        }
    }

L'échantillon 1 (tableau int) renvoie en {}tant que résultat JSON.

L'échantillon 2 renvoie le résultat attendu ["0","1","2","3","4","5","6","7","8","9"]. Cependant, l'intégralité du tableau JSON est retourné en une seule fois après 10 secondes d'attente. Ne doit-il pas être renvoyé lorsque les données deviennent disponibles comme prévu à partir de l'interface IAsyncEnumerable? Ou existe-t-il un moyen spécifique de consommer cette API Web?

Ravi M Patel
la source
4
Ne doit-il pas être renvoyé lorsque les données deviennent disponibles comme prévu à partir de l'interface IAsyncEnumerable? ... et c'est le cas ... mais pour le sérialiseur json
Selvin
1
et Sample 1 .... semble être un bug pour le type non référence (si vous passez IAsyncEnumerable<int>à IAsyncEnumerable<object>- cela devrait fonctionner mais il y a une boxe impliquée)
Selvin
@Selvin, pourriez-vous s'il vous plaît élaborer? Ou pointez-vous vers un exemple de code? J'ai essayé de consommer cette API avec le client C #, le résultat est le même, faut attendre 10 secondes ...
Ravi M Patel
dois attendre 10 secondes c'est obviosu ... la sérialisation est du côté serveur et ce n'est pas asynchrone ... élaborer sur quoi?
Selvin
1
le bogue est ... c'est évidemment pourquoi
Selvin

Réponses:

3

Un appel web api ne renverra pas json partiel toutes les secondes. C'est le sérialiseur json qui doit attendre 10 x 1 seconde (ou le code qui appelle le sérialiseur json, qui fait partie d'ASP .NET). Une fois que le code d'infrastructure et le sérialiseur auront obtenu toutes les données, il sera sérialisé et servi - en tant que réponse unique - au client.

Dans les types de retour d'action du contrôleur dans l'API Web ASP.NET Core, nous pouvons lire:

Dans ASP.NET Core 3.0 et versions ultérieures, retour de IAsyncEnumerable à partir d'une action:

  • N'entraîne plus d'itération synchrone.
  • Devient aussi efficace que renvoyant IEnumerable.

ASP.NET Core 3.0 et versions ultérieures mettent en mémoire tampon le résultat de l'action suivante avant de le fournir au sérialiseur:

public IEnumerable<Product> GetOnSaleProducts() =>
  _context.Products.Where(p => p.IsOnSale);
tymtam
la source