我有一个restful(webHttpBind)自托管WCF服务。大多数方法都将对象的xml或json版本返回给客户端。
我有几个触发长时间运行方法的GET方法,我想将日志响应流式传输到浏览器(或应用程序),以便用户知道发生了什么。这很容易通过HttpContext. Current.Response.OutputStream.Write
完成。不幸的是,在自托管的WCF服务中,HttpContext.当前
始终为空,即使我包含aspNetCom就是启用
配置(不幸的是,IIS不是一个选项)。
我尝试过匿名PipeServerStream
:WCF和流式请求和响应
连同第一个设置:
OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse;
context.ContentType = "text/plain";
以便响应进入浏览器,它不会将流下载到文件中保存。
Chrome它根本不起作用——它缓冲到最后。在IE或wget中,它似乎一次缓冲大约4k(或其他东西)。这对日志记录没有好处,因为除非我吐出大量不必要的日志消息来强制输出,否则用户并不真正知道发生了什么。我只能假设这是因为响应实际上是一个分块响应,并且分块4k(而不仅仅是写入输出流)。
让chrome输出的修复方法显然是在发送分块响应之前向内容写入一些垃圾:分块传输编码-浏览器行为,但是,我认为WCF不可能做到这一点。
因此,我正在寻找的可能解决方案:
我想,另一个选择是放弃WCF,转而使用对REST更友好的东西(我开始认为WCF不是正确的选择)。然而,现在用WCF写了这么多,这似乎是一项乏味的任务。除非有什么我可以切换到的东西,否则迁移会很容易(例如,如果我可以重用相同的服务类,也许只有不同的属性)。也许南希?
我已经做了一些像你在这里问的事情——也是自托管的。我编写了一个WCF(BasicHttpBind)服务,它可以将数据流式传输和缓冲到使用我的服务进行数据同步的客户端设备。正如你可能已经知道的那样,流式传输很难,我认为没有任何方法可以“写入流”。
基本上,通过WCF服务进行流式传输的工作方式与File.IO的工作方式相同,如下面的代码所示
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
如果有问题的文件是1 GB,您的文件流将在读取到文件末尾之前开始返回字节。通过WCF流式传输的工作方式相同(事实上,根据我的经验,它实现了FileStream),这就是为什么它适用于大量数据。它读取…它发送;它读取…它发送。所以我不确定你如何将一些信息注入到该流中以输出到屏幕。
话虽如此,我们的同步UI显示下降的字节数,加上完成百分比,以防止用户关闭机器或取消。我们通过让一个单独的线程每10秒读取下载文件的大小并计算整体的百分比(完整大小作为响应中的参数发送回来),然后将结果写入UI结果窗口来做到这一点。因此,在我们的例子中,解决方案实际上非常简单。
我这样做文件流:
将返回需要流式传输到endpoint的数据的方法分组,然后在该endpoint上添加流式传输模式。
这是我使用的配置(用于basicHttpBind)。
<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。
我还没有尝试过webHttp绑定,所以请让我知道它是否适合你。
只需欺骗浏览器认为有一个超文本标记语言响应与Multipart Content-Type
http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
我已经将它用于很多事情,包括MJPEG,但您也可以将它用于类似COMET/WebSocket的响应。