How do I write streamed output in NancyFX?

本小妞迷上赌 提交于 2019-12-05 23:45:14

问题


I'm writing a simple web application using Nancy. At least one request results in a stream of unknown length, so I can't provide Content-Length. I'd like to use Transfer-Encoding: chunked, or (equally acceptable in this case, Connection: close).

I've had a quick hack on the Nancy source code, and I've add Response.BufferOutput, and code to set HttpContext.Response.BufferOutput to false. You can see that here:

public class HomeModule : NancyModule
{
    public HomeModule()
    {
        Get["/slow"] = _ => new SlowStreamResponse();
    }

    private class SlowStreamResponse : Response
    {
        public SlowStreamResponse()
        {
            ContentType = "text/plain";
            BufferOutput = false;
            Contents = s => {
                byte[] bytes = Encoding.UTF8.GetBytes("Hello World\n");
                for (int i = 0; i < 10; ++i)
                {
                    s.Write(bytes, 0, bytes.Length);
                    Thread.Sleep(500);
                }
            };
        }
    }

It doesn't seem to have any effect. The response turns up all at once, after 5 seconds. I've tested this a simple WebRequest-based client.

How do I get chunked output to work in Nancy? I'm using the ASP.NET hosting, but I'd be interested in answers for the other hosting options.

If I write a simple server using HttpListener, I can set SendChunked to true, and it sends chunked output, which my simple client correctly receives in chunks.


回答1:


During my experimentation, I discovered that I needed the following configuration. First, set up your web.config file as documented in the Nancy Wiki. It is worth noting that in order to set the disableoutputbuffer value (which is what we want), it appears that you currently need to also specify a bootstrapper. Creating a class in your assembly that inherits from Nancy.Hosting.Aspnet.DefaultNancyAspNetBootstrapper and specifying it in the configuration file appears to work.

<configSections>
  <section name="nancyFx" type="Nancy.Hosting.Aspnet.NancyFxSection" />
</configSections>
<nancyFx>
  <bootstrapper assembly="YourAssembly" type="YourBootstrapper"/>
  <disableoutputbuffer value="true" />
</nancyFx>

Afterwards, you should not set the Transfer-Encoding header. Rather, the following route definition appears to correctly stream the results from my IIS Express development server to Chrome:

Get["/chunked"] = _ =>
{
  var response = new Response();
  response.ContentType = "text/plain";
  response.Contents = s =>
  {
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Hello World ");
    for (int i = 0; i < 10; ++i)
    {
      for (var j = 0; j < 86; j++)
      {
        s.Write(bytes, 0, bytes.Length);
      }
      s.WriteByte(10);
      s.Flush();
      System.Threading.Thread.Sleep(500);
    }
  };

  return response;
};

I specified more content per chunk than the previous example due to the minimum sizes prior to first render documented in other StackOverflow questions




回答2:


You have to call Flush() after each Write(), otherwise the response is buffered anyway. Moreover, Google Chrome doesn't render the output until it's all received.

I discovered this by writing a simple client application that logged what it was reading from the response stream as it arrived.




回答3:


If using .NET 4.5+, you can alternatively use Stream.CopyTo instead of flush.

Get["/chunked"] = _ =>
{
  var response = new Response();
  response.ContentType = "text/plain";
  response.Contents = s =>
  {
    using(var helloStream = new MemoryStream(Encoding.UTF8.GetBytes("Hello World ")))
      helloStream.CopyTo(s);
  }
  return response;
}


来源:https://stackoverflow.com/questions/11484873/how-do-i-write-streamed-output-in-nancyfx

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!