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

如何从带附件的SOAP响应中提取附件并保存为文件?

How to Extract and Save Attachments from a MIME-Multipart SOAP Response in C#

Hey there! Let's sort out how to properly grab that attachment from your SOAP response. The main issue with your current code is that you're using StreamReader (a text-focused reader) to process the entire response—this destroys binary data like your PDF, since text encoding can't preserve all byte values correctly. Plus, you need to parse the MIME multi-part structure instead of treating everything as a single string.

Step-by-Step Fix

First, let's break down what you need to do:

  • Parse the MIME boundary from the response headers
  • Process the raw response stream (not as text)
  • Identify the attachment part using its Content-ID or Content-Type
  • Extract the binary content and save it to a file

Option 1: Manual MIME Parsing (No External Libraries)

Here's a working implementation that handles the MIME structure manually:

using (WebResponse response = request.GetResponse())
{
    // Get the MIME boundary from the Content-Type header
    var contentType = response.Headers["Content-Type"];
    var boundary = contentType.Split(';').FirstOrDefault(p => p.Trim().StartsWith("boundary="))?
        .Split('=')[1].Trim().Replace("\"", "");
    if (string.IsNullOrEmpty(boundary))
        throw new InvalidOperationException("Could not find MIME boundary in response headers");

    using (var responseStream = response.GetResponseStream())
    using (var reader = new BinaryReader(responseStream))
    {
        var boundaryBytes = Encoding.ASCII.GetBytes($"--{boundary}");
        byte[] buffer = new byte[4096];
        int bytesRead;
        bool isAttachmentPart = false;
        bool skipHeaders = false;

        using (var fileStream = new FileStream(HttpContext.Current.Server.MapPath("/test.pdf"), FileMode.Create))
        {
            while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
            {
                // Check if we've hit a boundary
                var boundaryIndex = FindBufferIndex(buffer, bytesRead, boundaryBytes);
                if (boundaryIndex != -1)
                {
                    isAttachmentPart = false;
                    skipHeaders = false;
                    // Read past the boundary and check the next part's headers
                    var remainingBytes = bytesRead - boundaryIndex - boundaryBytes.Length;
                    if (remainingBytes > 0)
                    {
                        // Process the remaining data to check headers
                        var headerBuffer = new byte[remainingBytes];
                        Array.Copy(buffer, boundaryIndex + boundaryBytes.Length, headerBuffer, 0, remainingBytes);
                        var headerText = Encoding.ASCII.GetString(headerBuffer);
                        // Check if this part is the attachment (match Content-ID or Content-Type)
                        if (headerText.Contains("Content-ID: <urn:uuid:C455EAC131FBC506CE1521805985219>") ||
                            headerText.Contains("Content-Type: application/octet-stream"))
                        {
                            isAttachmentPart = true;
                            skipHeaders = true;
                        }
                    }
                }
                else if (isAttachmentPart)
                {
                    if (skipHeaders)
                    {
                        // Skip the headers (look for the empty line that separates headers from content)
                        var emptyLineIndex = FindBufferIndex(buffer, bytesRead, Encoding.ASCII.GetBytes("\r\n\r\n"));
                        if (emptyLineIndex != -1)
                        {
                            skipHeaders = false;
                            // Write the content after the empty line
                            fileStream.Write(buffer, emptyLineIndex + 4, bytesRead - emptyLineIndex - 4);
                        }
                    }
                    else
                    {
                        // Write the binary content to the file
                        fileStream.Write(buffer, 0, bytesRead);
                    }
                }
            }
        }
    }
}

// Helper method to find a byte sequence in a buffer
private static int FindBufferIndex(byte[] buffer, int bufferLength, byte[] searchBytes)
{
    for (int i = 0; i <= bufferLength - searchBytes.Length; i++)
    {
        bool match = true;
        for (int j = 0; j < searchBytes.Length; j++)
        {
            if (buffer[i + j] != searchBytes[j])
            {
                match = false;
                break;
            }
        }
        if (match)
            return i;
    }
    return -1;
}

Key Notes for Manual Parsing:

  • We use BinaryReader instead of StreamReader to handle raw bytes without encoding corruption
  • The MIME boundary is extracted from the Content-Type header of the response
  • We scan the stream to find each boundary, then check the part headers to identify the attachment
  • We skip the headers (up to the empty line) before writing the binary content to the file

Option 2: Use a Library (Simpler & More Reliable)

Manual MIME parsing can get messy (handling different encodings, line endings, etc.). A better approach is to use a dedicated MIME parsing library like MimeKit:

  1. First, install the MimeKit NuGet package:
Install-Package MimeKit
  1. Then use this code to parse the response:
using (WebResponse response = request.GetResponse())
using (var responseStream = response.GetResponseStream())
{
    // Parse the entire MIME message
    var message = MimeMessage.Load(responseStream);
    
    // Find the attachment part (match by Content-ID or Content-Type)
    var attachment = message.BodyParts.OfType<MimePart>().FirstOrDefault(part =>
        part.ContentId == "<urn:uuid:C455EAC131FBC506CE1521805985219>" ||
        part.ContentType.MimeType == "application/octet-stream");
    
    if (attachment != null)
    {
        // Save the attachment to file
        using (var fileStream = new FileStream(HttpContext.Current.Server.MapPath("/test.pdf"), FileMode.Create))
        {
            attachment.Content.DecodeTo(fileStream);
        }
    }
}

This is way cleaner and handles all edge cases (like different content transfer encodings) automatically.

Why Your Original Code Failed:

  • StreamReader.ReadToEnd() converts the binary attachment to a string using ASCII encoding, which replaces unrepresentable bytes with ?—permanently corrupting the PDF data
  • You tried converting this corrupted string back to bytes and treating it as Base64, but the attachment wasn't Base64 encoded (it's marked as binary transfer encoding)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:57:02