如何在不缓冲的情况下从WCF流式传输响应?

时间:2014-05-12 08:58:01

标签: c# .net wcf rest stream

我有一个restful(webHttpBinding)自托管WCF服务。大多数方法都是将xml或json版本的对象返回给客户端。

我有几个触发长时间运行方法的GET方法,我想将日志响应流式传输到浏览器(或应用程序),以便用户知道发生了什么。使用HttpContext.Current.Response.OutputStream.Write可以很容易地实现这一点。遗憾的是,HttpContext.Current在自托管WCF服务中始终为空,即使我包含aspNetCompatibilityEnabled配置(遗憾的是IIS不是一个选项)。

我试过AnonymousPipeServerStreamWCF and streaming requests and responses

以及第一次设置:

OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse;
context.ContentType = "text/plain";

以便响应进入浏览器,它不会将流下载到文件中进行保存。

在Chrome中根本不起作用 - 它会一直缓存到最后。在IE或wget中,它似乎一次缓冲大约4k(或其他东西)。这对于日志记录没有好处,除非我吐出大量不必要的日志消息以强制输出,用户并不真正知道发生了什么。我只能假设这是因为响应实际上是一个分块响应而且块是4k(而不是只写入输出流)。

将chrome输出到输出的修复显然是在发送分块响应之前给内容写了一些垃圾:Chunked transfer encoding - browser behavior但是,我不认为这可以通过WCF实现。

所以,我正在寻找可能的解决方案:

  • 一种在自托管服务(无IIS)中写入WCF中的输出流的方法。 或
  • 一种控制流响应中块大小的方法(以及首先编写某些内容以便Chrome将呈现块的方式)。

我认为,另一个选择是放弃WCF,转而支持更友好的REST(我开始认为WCF不是正确的选择)。但是,现在在WCF中写了这么多,这似乎是一项繁琐的工作。除非有一些我可以切换到的东西,这将是一个简单的迁移(例如,如果我可以重用相同的服务类,可能只有不同的属性)。南希可能吗?

3 个答案:

答案 0 :(得分:2)

我做过类似你在这里问的事情 - 自我托管。我写了一个WCF(BasicHttpBinding)服务,它将数据的流式传输和缓冲都用于消费我的数据同步服务的客户端设备。流媒体很难,正如你可能已经想到的那样,而且我认为没有任何方式可以写入流媒体"。

从基本的意义上讲,通过WCF服务进行流式传输的方式与File.IO的工作方式相同,如下面的代码所示

 FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
 BinaryReader br = new BinaryReader(fs);

如果有问题的文件是1 GB,您的文件流将在读取到文件末尾之前开始返回字节。通过WCF流​​式传输的工作方式相同(实际上,根据我的经验,它实现了FileStream),这就是为什么它对大量数据有利。它读取......它发送;它读...它发送。因此,我不确定您是如何将某些信息注入到该流中以输出到您的屏幕上的。

话虽如此,我们的Synch UI会显示下降的字节数,加上完成百分比,以防止用户关闭机器或取消。我们这样做是通过让一个单独的线程每10秒读取下载文件的大小并计算整体的百分比(完整的大小作为响应中的参数发回),然后将结果写入UI结果窗口。因此,在我们的案例中,解决方案实际上非常简单。

答案 1 :(得分:0)

我像这样传输文件:

将返回需要流式传输的数据的方法分组到端点,然后在该端点上添加流式传输模式。

这是我使用的配置(用于basicHttpBinding)。

<services>
  <service name="CustomersService">
    <endpoint address="FilesService.svc" binding="basicHttpBinding" bindingConfiguration="StreamedBinding" contract="Soap.Interfaces.IFilesService" />
  </service>
</services>

并定义绑定配置:

<bindings>
    <basicHttpBinding>
        <binding name="IntersolveWebServicesStreamedBinding" allowCookies="true" transferMode="Streamed" maxReceivedMessageSize="67108864" />
    </basicHttpBinding>
</bindings>

基本上,您必须在绑定配置中设置transferMode。

我没有尝试使用webHttpBinding,所以请告诉我它是否适合您。

答案 2 :(得分:0)

只需欺骗浏览器即可认为存在Multipart Content-Type

的HTML响应

http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html

我已经将它用于包括MJPEG在内的很多东西,但你也可以将它用于COMET / WebSocket之类的响应。