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

如何在.NET Framework 4.8/.NET Core中用HttpClient发送带PDF附件的SOAP API请求?

问题分析

你遇到的错误是因为服务端的documentData字段被定义为base64Binary类型,但你的请求中直接传入了cid:NETRoadmap.pdf字符串,不符合MTOM(Message Transmission Optimization Mechanism)的规范。SOAP UI启用MTOM后正常,说明服务端支持MTOM传输,你需要按照MTOM的格式构建请求,而非普通的multipart附件。

解决方案

方案1:使用WCF客户端(推荐,原生支持MTOM)

.NET Framework中WCF对MTOM有原生支持,相比手动构建请求更简单可靠:

  1. 添加服务引用
    在项目右键 → 添加 → 服务引用,输入SOAP API的WSDL地址,生成客户端代理类。

  2. 配置MTOM绑定
    修改App.config或Web.config的绑定配置,启用MTOM:

    <system.serviceModel>
      <bindings>
        <basicHttpBinding>
          <binding name="YourServiceBinding" messageEncoding="Mtom">
            <!-- 根据服务要求配置其他属性,比如安全、超时等 -->
          </binding>
        </basicHttpBinding>
      </bindings>
      <client>
        <endpoint address="soapapiurl" binding="basicHttpBinding" bindingConfiguration="YourServiceBinding" contract="YourServiceNamespace.YourServiceContract" />
      </client>
    </system.serviceModel>
    
  3. 调用API上传文件
    使用生成的客户端类直接传入文件字节数组:

    public static void Main(string[] args)
    {
        string filePath = @"D:\C#Projects\CarFinanceFiles\NETRoadmap.pdf";
        byte[] fileBytes = File.ReadAllBytes(filePath);
    
        using (var client = new YourServiceClient())
        {
            var request = new SendDocumentRequest
            {
                documentUploader = new DocumentUploader
                {
                    fileType = "PAY",
                    documentName = "NETRoadmap",
                    documentData = fileBytes
                }
            };
    
            try
            {
                var response = client.SendDocument(request);
                Console.WriteLine("上传成功");
                // 处理响应
            }
            catch (Exception ex)
            {
                Console.WriteLine($"错误:{ex.Message}");
            }
        }
    }
    

方案2:手动构建MTOM格式的HttpClient请求

如果必须使用HttpClient手动构建请求,需要按照MTOM规范调整SOAP信封和请求头:

修改后的代码如下:

public class Program
{
    public static async Task Main(string[] args)
    {
        string serviceUrl = "soapapiurl";
        string boundary = $"----=_Part_{Guid.NewGuid():N}";
        string soapPartCid = "<soapPart>";
        string attachmentCid = "<NETRoadmap.pdf>";

        // 读取文件
        string filePath = @"D:\C#Projects\CarFinanceFiles\NETRoadmap.pdf";
        byte[] fileBytes = File.ReadAllBytes(filePath);

        // 构建符合MTOM规范的SOAP信封,使用xop:Include引用附件
        string soapEnvelope = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" 
                                                   xmlns:vo=""http://vo.service.ws.proposal.wcg.com""
                                                   xmlns:xop=""http://www.w3.org/2004/08/xop/include"">
  <soapenv:Header/>
  <soapenv:Body>
    <vo:SendDocumentRequest>
      <vo:documentUploader>
        <vo:fileType>PAY</vo:fileType>
        <vo:documentName>NETRoadmap</vo:documentName>
        <vo:documentData>
          <xop:Include href=""cid:NETRoadmap.pdf"" />
        </vo:documentData>
      </vo:documentUploader>
    </vo:SendDocumentRequest>
  </soapenv:Body>
</soapenv:Envelope>";

        // 创建multipart/related内容,符合MTOM要求
        var multipartContent = new MultipartContent("related", boundary);
        multipartContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("type", "\"application/xop+xml\""));
        multipartContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("start", soapPartCid));
        multipartContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("start-info", "\"text/xml\""));

        // 添加SOAP部分
        var soapContent = new StringContent(soapEnvelope, Encoding.UTF8, "application/xop+xml");
        soapContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8"));
        soapContent.Headers.Add("Content-ID", soapPartCid);
        multipartContent.Add(soapContent);

        // 添加附件部分
        var attachmentContent = new ByteArrayContent(fileBytes);
        attachmentContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        attachmentContent.Headers.Add("Content-ID", attachmentCid);
        // 不需要Content-Disposition,MTOM依赖Content-ID关联
        multipartContent.Add(attachmentContent);

        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("SOAPAction", "SendDocument");
            
            HttpResponseMessage response = await client.PostAsync(serviceUrl, multipartContent);

            if (response.IsSuccessStatusCode)
            {
                string responseContent = await response.Content.ReadAsStringAsync();
                Console.WriteLine("响应内容:");
                Console.WriteLine(responseContent);
            }
            else
            {
                Console.WriteLine($"错误状态码:{response.StatusCode}");
                string errorContent = await response.Content.ReadAsStringAsync();
                Console.WriteLine(errorContent);
            }
        }
    }
}

关键修改点:

  • SOAP信封中使用<xop:Include href="cid:NETRoadmap.pdf" />替代直接写cid:...,符合MTOM对二进制数据的引用规范
  • 设置multipart内容的Content-Type为multipart/related,并添加type="application/xop+xml"、start和start-info参数
  • SOAP部分的Content-Type改为application/xop+xml,并设置对应的Content-ID
  • 附件部分仅保留Content-Type和Content-ID,不需要Content-Disposition(MTOM通过Content-ID关联,而非附件 disposition)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 10:39:52