简体   繁体   中英

How do I parse a MIME message from a HttpResponseMessage in C#?

After successfully sending a status inquiry...

using (var client = new HttpClient(handler))
{
    var mime = new MultipartFormDataContent("myBoundary");

    var attachment = new StringContent(envelope);
    // add headers to attachment
    
    mime.Add(attachment);

    var response = await client.PostAsync("/endpoint", mime);
}

... I recieve the following response.

Content --MIME-Multipart-Boundary
Content-Type: application/xop+xml; charset=iso-8859-1
Content-Id: RootPart
Content-Transfer-Encoding: binary

<?xml version="1.0" encoding="iso-8859-1"?>
<soapenv:Envelope>
    <soapenv:Header />
    <soapenv:Body>
        <xres:Transport>
            <xres:TransportBody>
                <xres:Package>
                    <xcpt:Data>
                        <xcpt:Base64CharSequence>
                            <inc:Include href="cid:efcd94e7-9acc-4f5a-bfe9-2bf592b591c6" />
                        </xcpt:Base64CharSequence>
                    </xcpt:Data>
                </xres:Package>
            </xres:TransportBody>
        </xres:Transport>
    </soapenv:Body>
</soapenv:Envelope>
--MIME-Multipart-Boundary
Content-Type: application/octet-stream
Content-Length: 9999
Content-Id: efcd94e7-9acc-4f5a-bfe9-2bf592b591c6
Content-Transfer-Encoding: binary

For the sake of simplicity, this sentence is used here instead of the actual binary data
--MIME-Multipart-Boundary--

The <xres:TransportBody>...</xres:TransportBody> contains n packages. Each package contains a cid ( content-id ), which references the related MIME attachment with the same cid.

After some time I came along MimeKit , which hopefully relieves me from my suffering. Anyways, no matter how promising MimeKit looks to me, I can't parse the MIME message correctly. The multipart variable always has a count of zero elements.

var content = await response.Content.ReadAsStringAsync();

var contentBytes = Encoding.ASCII.GetBytes(content);

var contentType = ContentType.Parse(response.Content.Headers.ContentType!.MediaType);

using (var ms = new MemoryStream(contentBytes, false))
{
    var multipart = MimeEntity.Load(contentType, ms) as Multipart;

    // Nothing to iterate, so it skips the foreach loop
    foreach (var attachment in multipart.OfType<MimePart>())
    {
        using (var attachmentMs = new MemoryStream())
        {
            attachment.Content.DecodeTo(attachmentMs);
        }
    }
}

Question: Does anybody knows how I could parse the above MIME message using MimeKit ?

I highly appreciate any kind of help, cheers!


Update:

Apparently, await response.Content.ReadAsStringAsync() returns a slightly different result compared to the actual response object. The response object has the correct header Content-Type: multipart/related; boundary=MIME-Multipart-Boundary Content-Type: multipart/related; boundary=MIME-Multipart-Boundary .

So it seems as if important information is being lost in the parsing process of the response object. I've already tried some different approaches, but all resulted in the same "error".

// Approach 1
await response.Content.ReadAsStringAsync()

// Approach 2
var parsedResponse = response.Content.ReadAsStream();
StreamReader reader = new StreamReader(parsedResponse);
Console.WriteLine(reader.ReadLine());

// Approach 3
var parsedResponse = response.Content.ReadAsStreamAsync();
StreamReader reader = new StreamReader(parsedResponse);
Console.WriteLine(reader.ReadLine());

Am I doing something wrong - How do I get the actual response data?


Update:

As jdweng mentioned in the comments...

Using String methods or Encoding methods on binary data will corrupt the data.

Therefore I came up with the following approach, which now takes in all 11137 bytes of the response - So, no more missing information (hopefully).

using (var ms = new MemoryStream(await response.Content.ReadAsByteArrayAsync()))
{
    ms.Position = 0;

    // Could get the correct MediaType here: multipart/related
    var contentType = ContentType.Parse(response.Content.Headers.ContentType!.MediaType);

    // Could not get the correct boundary. Boundary is null here
    var multipart = MimeEntity.Load(contentType, ms) as Multipart;
    
    // Only thing left, is to get the boundary automatically
    contentType.Boundary = "MIME-Multipart-Boundary";

    // Nothing to iterate, so it skips the foreach loop
    foreach (var attachment in multipart.OfType<MimePart>())
    {
        using (var attachmentMs = new MemoryStream())
        {
            attachment.Content.DecodeTo(attachmentMs);
        }
    }
}
using (var ms = new MemoryStream(await response.Content.ReadAsByteArrayAsync()))
{
    // Set the position of the memory stream to zero
    ms.Position = 0;

    // Set the MediaType (multipart/related)
    var contentType = ContentType.Parse(response.Content.Headers.ContentType!.MediaType);

    // Set the boundary of the ContentType
    contentType.Boundary = "MIME-Multipart-Boundary";

    var multipart = MimeEntity.Load(contentType, ms) as Multipart;

    foreach (var attachment in multipart.OfType<MimePart>())
    {
        using (var attachmentMs = new MemoryStream())
        {
            attachment.Content.DecodeTo(attachmentMs);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM