0

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.

Dmitry Nogin
  • 3,670
  • 1
  • 19
  • 35
  • Does this help? http://stackoverflow.com/questions/25429726/httpclient-and-pushstreamcontent It seems like a request header fixed this guy's problem. – ps2goat Jul 18 '15 at 03:25
  • He mentions client configuration as far as I can see. I have no control over web browser, but I saw browsers progressively rendering text files while loading them. It should be something about server side. – Dmitry Nogin Jul 18 '15 at 03:34
  • But is your request coming from an ajax post, and from a site you control? If so, you can add headers to the request. http://stackoverflow.com/questions/7686827/how-can-i-add-a-custom-http-header-to-ajax-request-with-js-or-jquery – ps2goat Jul 18 '15 at 05:11
  • 1
    No, I have no client control. Since days of old web browsers rendered text files progressively. Is it really necessary to adjust anything on the browser side? – Dmitry Nogin Jul 18 '15 at 05:51
  • See [this](http://stackoverflow.com/questions/9600856/how-to-deliver-big-files-in-asp-net-response) post. – Yuval Itzchakov Jul 18 '15 at 07:27
  • Disabling gzip did not help. It looks like flashing does not work - please see the update. – Dmitry Nogin Jul 18 '15 at 11:42

1 Answers1

0

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).

user901366
  • 91
  • 2
  • 12