ASP.NET Web API Controller output is always buffer

2019-08-29 06:07发布

How to send output without buffering? I defined my API controller this way:

public class DefaultController : ApiController
{
    [HttpGet]
    [Route]
    public HttpResponseMessage Get()
    {
        var response = Request.CreateResponse();
        response.Content = new PushStreamContent(
            (output, content, context) =>
            {
                using (var writer = new StreamWriter(output))
                {
                    for (int i = 0; i < 5; i++)
                    {
                        writer.WriteLine("Eh?");
                        writer.Flush();
                        Thread.Sleep(2000);
                    }
                }
            },
            "text/plain");

        return response;
    }
}

Output appears in the browser all at once, so it looks like it waits start sending it till completion. I defined this attribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class NoBufferAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        controllerSettings.Services.Replace(
            typeof(IHostBufferPolicySelector),
            new BufferPolicy());
    }

    class BufferPolicy : IHostBufferPolicySelector
    {
        public bool UseBufferedInputStream(object hostContext)
        {
            return false;
        }

        public bool UseBufferedOutputStream(HttpResponseMessage response)
        {
            return false;
        }
    }
}

And applied it to controller:

    [NoBuffer]
    public class DefaultController : ApiController
    {
          ...
    }

It did not help. All the output appears in the browser the same time.

UPDATE

It looks like problem is about flushing. I changed code to the following:

        var response = Request.CreateResponse();
        response.Content = new PushStreamContent(
            (output, content, context) =>
            {
                using (var writer = new StreamWriter(output))                    
                {
                    var s = Stopwatch.StartNew();
                    while (s.Elapsed < TimeSpan.FromSeconds(10))
                    {
                        writer.WriteLine(s.Elapsed);
                        writer.Flush();                            
                    }
                }
            },
            "text/plain");

Now I can see output in progress. Disabling gzip encoding does not help to see content in smaller chunks.

1条回答
走好不送
2楼-- · 2019-08-29 06:16

Please, try 'text/event-stream' for mediaType parameter of PushStreamContent constructor:

public class DefaultController : ApiController
{
    [HttpGet]
    [Route]
    public HttpResponseMessage Get()
    {
        var response = Request.CreateResponse();
        response.Content = new PushStreamContent(
            (output, content, context) =>
            {
                using (var writer = new StreamWriter(output))
                {
                    for (int i = 0; i < 5; i++)
                    {
                        writer.WriteLine("Eh?");
                        writer.Flush();
                        Thread.Sleep(2000);
                    }
                }
            },
            "text/event-stream");

        return response;
    }
}

This has worked for me (using .net 4.6.1).

查看更多
登录 后发表回答