You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C#从SOAP响应提取MTOM/XOP附件并保存为PDF

处理MTOM/XOP格式SOAP响应中的PDF附件(C#实现)

问题背景

需要从包含MTOM(XOP)附件的SOAP响应中提取PDF文档,反序列化XOP得到二进制数据并保存为PDF文件。当前使用StreamReader读取响应的方式无法正确处理二进制附件,但SoapUI开启“Expand MTOM Attachment”可正常获取PDF,寻求C#可行实现方案。

收到的SOAP响应

--uuid:277c111e-1c6c-4da9-9e54-95ec1073550e
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns="http://www.endpoint.com/api/">
<soapenv:Header>
    <ResponseHeader state="OK" timelasted="116"/>
</soapenv:Header>
<soapenv:Body>
    <GetDocumentResponse>
        <idDocument>1</idDocument>
        <content>
            <mime>application/pdf</mime>
            <name>document.pdf</name>
            <data fileSize="15756">
                <inc:Include
                    xmlns:inc="http://www.w3.org/2004/08/xop/include" href="cid:1234"/>
                </data>
            </content>
        </GetDocumentResponse>
    </soapenv:Body>
</soapenv:Envelope>
    
--uuid:277c111e-1c6c-4da9-9e54-95ec1073550e
Content-Type: application/pdf
Content-Transfer-Encoding: binary
Content-ID: <1234>

۞t�:�=��M��=��������۝��M��
��M��N��n��
��-��^��^���8ﮅ�n����Nt�^�랂�݅�~�략�m��^��N��~��Nt���N�M��^t�n����~��m��^��N��~��Nt�:�N��^��M��N9獴�m��M��M��݅�~�략�^�㎵��8�
��M��}��M��]�ߝ�����M��M�۽��M��݅�>��8�^�라���m��m��]��}��]��]�ߝ����M��M�۽��^x�z�^<��8���ߍ�ߝ�߭��M��}��^x�z�^7�>t�~�9�ͽ�^x�z�^w�5�nx�5�9�ͽ�M��=

现有C#请求代码片段

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(endpoint);
req.Headers.Add("SOAP:Action");
req.ContentType = "text/xml;charset=utf-8";
req.Method = "POST";
req.Accept = "application/pdf";
req.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes("username:password"));
req.Credentials = new NetworkCredential(username, password);

var soapRequest = @"XML_Request";

using (StreamWriter writer = new StreamWriter(req.GetRequestStream()))
{
    writer.Write(soapRequest);
}
using (var httpResponse = (HttpWebResponse)req.GetResponse())
{
    var streamReader = new StreamReader(httpResponse.GetResponseStream());
    result = streamReader.ReadToEnd();
}

解决方案

MTOM响应是多部分MIME消息,不能直接用StreamReader读取文本,需要解析多部分内容,匹配cid找到对应的PDF附件流。

关键步骤

  • 调整请求头:将Accept设置为multipart/related; type="application/xop+xml",明确告知服务端返回MTOM格式响应。
  • 解析多部分响应:使用MultipartMemoryStreamProvider自动分割多部分内容,将每个部分封装为可操作的对象。
  • 提取并保存PDF:遍历所有响应部分,匹配SOAP中inc:Include指向的cid值,将对应部分的二进制流保存为PDF文件。

完整示例代码

using System;
using System.IO;
using System.Net;
using System.Net.Mime;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        string endpoint = "你的API端点地址";
        string username = "用户名";
        string password = "密码";
        var soapRequest = @"你的SOAP请求XML内容";

        // 创建请求并配置参数
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(endpoint);
        req.Headers.Add("SOAPAction", ""); // 替换为实际的SOAP Action值
        req.ContentType = "text/xml;charset=utf-8";
        req.Method = "POST";
        // 设置Accept头支持MTOM格式
        req.Accept = "multipart/related; type=\"application/xop+xml\"";
        req.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
        req.Credentials = new NetworkCredential(username, password);

        // 发送SOAP请求
        using (StreamWriter writer = new StreamWriter(req.GetRequestStream()))
        {
            writer.Write(soapRequest);
        }

        // 处理MTOM响应
        using (var httpResponse = (HttpWebResponse)req.GetResponse())
        {
            if (httpResponse.ContentType.StartsWith("multipart/related"))
            {
                var provider = new MultipartMemoryStreamProvider();
                using (var responseStream = httpResponse.GetResponseStream())
                {
                    provider.ReadStreamAsync(responseStream, httpResponse.ContentType, null).Wait();
                }

                // 遍历所有响应部分,匹配目标cid
                foreach (var part in provider.Contents)
                {
                    var contentId = part.Headers.ContentId;
                    // 匹配SOAP中cid:1234对应的Content-ID(格式为<1234>)
                    if (contentId == "<1234>")
                    {
                        // 保存二进制内容为PDF文件
                        using (var fileStream = new FileStream("document.pdf", FileMode.Create))
                        {
                            part.CopyToAsync(fileStream).Wait();
                        }
                        Console.WriteLine("PDF文件已成功保存");
                        break;
                    }
                }
            }
            else
            {
                Console.WriteLine("响应并非MTOM格式");
            }
        }
    }
}

代码说明

  • 请求头优化:Accept设置为MTOM专属格式,确保服务端返回正确的多部分响应。
  • MultipartMemoryStreamProvider:自动处理多部分MIME的边界分割,无需手动解析原始流。
  • cid匹配逻辑:SOAP中的inc:Include指向cid:1234,对应附件的Content-ID为<1234>,需精确匹配该值才能定位到目标PDF流。

内容的提问来源于stack exchange,提问作者JohnB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 22:24:54