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