azureasp.net-core

IAsyncEnumerable JSON streaming is not streaming on azure web app running on IIS


I'm trying to make IAsyncEnumerable work while deployed to Azure and Windows/IIS. I made it work on localhost and on Linux on Azure. But when I deploy it to Windows the streaming isn't streaming - Client get first "message" and than all the rest at once at the end of the stream.

I tried to set WEBSITE_DYNAMIC_COMPRESSION to 0 for a web app with no luck. Also I had issues on Localhost, because I had response compression engaged. After turning it off it worked. There seems to be very little materials online how to trouble shoot this.

Anyone has idea what is wrong here?

Here is my fork of sample code https://github.com/vmachacek/angular12-dotnet6-streaming-json


Solution

  • After testing, we can use HttpContext.Features.Get<IHttpResponseBodyFeature>().DisableBuffering(); to fix the issue.

    Here is my test code

    using Microsoft.AspNetCore.Http.Features;
    using Microsoft.AspNetCore.Mvc;
    using System.Text.Json;
    
    namespace WebApplication2.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class TestController : ControllerBase
        {
            private readonly ILogger<TestController> _logger;
    
            public TestController(ILogger<TestController> logger)
            {
                _logger = logger;
            }
            [HttpGet("numbers")]
            public async IAsyncEnumerable<Wrapper> GetNumbers()
            {
                HttpContext.Features.Get<IHttpResponseBodyFeature>().DisableBuffering();
                await foreach (var r in FetchItems())
                {
                    yield return r;
                }
            }
    
            static async IAsyncEnumerable<Wrapper> FetchItems()
            {
                Wrapper wrapper = new Wrapper();
                for (int i = 1; i <= 10; i++)
                {
                    wrapper.Number = i;
                    wrapper.Content = "Content " + i;
                    await Task.Delay(1000);
                    yield return wrapper;
                }
            }
        }
        public class Wrapper
        {
            public int Number { get; set; }
            public string Content { get; set; }
        }
    }