WCF服务如何接收XML文件 WCF如何处理流式传输

10次阅读

WCF流式传输xml文件必须使用唯一stream参数、TransferMode.Streamed绑定、禁用MTOM,并通过临时文件或Raw模式解析,否则将静默退入缓冲模式导致内存溢出。

WCF服务如何接收XML文件 WCF如何处理流式传输

WCF 服务接收 XML 文件,本质是接收二进制流(Stream),而非直接反序列化为 XDocumentXmlDocument —— 否则就失去大文件处理能力,且极易触发 OutOfMemoryException。流式传输不是“可选优化”,而是处理 >10 MB XML 文件的**唯一可行路径**。

OperationContract 必须严格满足流式契约规则

WCF 的流式传输在编程模型层由契约强制约束,违反任一条件都会静默退回到缓冲模式(即整个 XML 加载进内存),且无警告。

  • Stream 参数或返回值必须是**唯一参数/返回值**:不能带其他 String fileNameint timeout 等辅助参数
  • 若需传递元数据(如文件名、编码、校验码),只能通过 MessageHeader 或 URL 查询参数(http 场景)传入
  • 服务端方法签名示例(合法):
[OperationContract] void UploadXmlFile(Stream xmlStream);
  • 错误写法(触发缓冲):void UploadXmlFile(Stream xmlStream, string filename) —— 编译通过,但运行时失效

Binding 的 TransferMode 必须显式设为 Streamed

仅改契约不够。默认所有绑定(如 BasicHttpBinding)都是 TransferMode.Buffered,此时即使参数是 Stream,WCF 仍会把整个 XML 读进内存再交给你的方法。

  • 必须在服务端和客户端**两端同步设置**:TransferMode.Streamed(双向流)、StreamedRequest(仅上传)、StreamedResponse(仅下载)
  • HTTP 场景下,BasicHttpBindingCustomBinding 支持该属性;NetTcpBinding 同样支持
  • 配置示例(app.config):
    
  • maxReceivedMessageSize 必须同步调大(单位字节),否则超限直接抛 QuotaExceededException

XML 文件不能直接用 XmlReader.Read() 读取原始 Stream

WCF 流式传输的 Stream 是经过 SOAP 封装的(尤其启用 MTOM 时),它不是裸 XML 字节流 —— 直接丢给 XmlReader.Create(stream) 会报 Root element is missing 或乱码。

  • 正确做法:先用 MessageEncoder 解包,或更实际地——**禁用 SOAP 封装,改用 Raw 模式**
  • 在绑定中启用 WebHttpBinding + [WebInvoke],并设置 BodyStyle = WebMessageBodyStyle.Bare
  • 或使用自定义 MessageEncoder 提取原始 XML 字节(复杂,仅必要时)
  • 最简方案(推荐):服务端接收 Stream 后,先保存为临时文件,再用 XmlReader.Create(File.OpenRead(tempPath)) 安全解析

MTOM 编码对 XML 传输的实际影响

MTOM(Message Transmission Optimization Mechanism)专为含二进制内容的 SOAP 消息设计,但它对纯文本 XML 文件**几乎无收益,反而增加解析负担**。

  • MTOM 要求操作契约**只能有单个 Stream 参数/返回值**(与前述规则重叠),且必须配合 text/xmlapplication/soap+xml 以外的 message/unknown MIME 类型
  • 对 UTF-8 XML,MTOM 附件机制会引入 Base64 编码开销(+33%体积)+ SOAP 包裹头,整体比原始 HTTP POST 更慢
  • 除非你的“XML 文件”实际是 ZIP 压缩包或含 Base64 内嵌图片的富文档,否则应禁用 MTOM,用普通 Stream + WebHttpBinding 更轻量

真正卡住多数人的不是“怎么写”,而是“为什么没生效”——WCF 流式传输失败时不会报错,只是悄悄吃掉内存。务必用 Process Explorer 观察服务进程私有字节数,上传 100MB 文件时若内存上涨超 150MB,说明流式未生效,立刻回查 TransferMode 和契约参数数量。

text=ZqhQzanResources