如何从MTOM读取器(XmlDictionaryReader)中提取文件?
在C#/.NET中提取MTOM响应中的MIME附件并保存为文件
核心解决方案(手动处理MTOM流)
如果你已经拿到了MTOM响应的字节数组,不要尝试用ReadElementContentAsString读取二进制数据——MTOM的附件是通过XOP(XML二进制优化打包)以MIME分块传输的,需要识别xop:Include元素来提取附件:
using System; using System.IO; using System.Xml; public void SaveMtomAttachment(byte[] mtomResponseBytes, string outputPath) { using var responseStream = new MemoryStream(mtomResponseBytes); // 创建MTOM读取器,设置最大配额避免读取大文件时受限 using var mtomReader = XmlDictionaryReader.CreateMtomReader( responseStream, XmlDictionaryReaderQuotas.Max ); // 遍历XML节点,定位xop:Include元素 while (mtomReader.Read()) { // 匹配xop:Include元素(注意命名空间必须正确) if (mtomReader.IsStartElement("Include", "http://www.w3.org/2004/08/xop/include")) { // 读取附件的Content-ID(可选,用于区分多附件场景) string contentId = mtomReader.GetAttribute("href").TrimStart("cid:".ToCharArray()); // 读取二进制附件数据,自动解码MIME分块内容 mtomReader.ReadStartElement(); byte[] attachmentBytes = mtomReader.ReadContentAsBase64(); // 写入文件 File.WriteAllBytes(outputPath, attachmentBytes); break; // 单附件场景找到后退出循环,多附件则去掉break并处理每个Include } } }
关键注意事项
- 不要直接读取标签内容:如果你的响应XML中
<Data>节点包含的是xop:Include而非内嵌Base64,直接读字符串会得到XML片段而非二进制数据,必然报错。 - 必须匹配xop命名空间:
xop:Include的命名空间固定为http://www.w3.org/2004/08/xop/include,忽略命名空间会导致无法识别该元素。 - 处理多附件:如果响应包含多个附件,去掉代码中的
break,根据每个xop:Include的href属性(Content-ID)生成不同的文件名保存。
更简便的WCF客户端场景
如果是通过WCF调用服务并接收MTOM响应,直接在消息契约中标记XmlMimeType属性,WCF会自动解析附件:
using System.ServiceModel; using System.Xml.Serialization; // 定义消息契约 [MessageContract(IsWrapped = false)] public class FileDownloadResponse { [MessageBodyMember(Name = "FileData", Namespace = "YourServiceNamespace")] [XmlMimeType("application/octet-stream")] // 指定MIME类型 public byte[] Attachment { get; set; } } // 调用服务后直接保存 var client = new YourServiceClient(); var response = client.DownloadFile(); File.WriteAllBytes("output.file", response.Attachment);
内容的提问来源于stack exchange,提问作者Max von der Mühle
相关产品推荐
相关产品推荐

