Read multipart/mixed in C# (.NET 4.0)

11,235

Solution 1

Use ReadAsMultipartAsync in the System.Net.Http.Formatting assembly, along the lines of

var content   = new StreamContent (stream) ;
var multipart = await content.ReadAsMultipartAsync () ;
foreach (var part in multipart)
{
    if (part.Headers.ContentType.MediaType == "application/json")
    {
        // deserialize via stream e.g. part.ReadAsStreamAsync () or via string
        // using part.ReadAsStringAsync () to avoid charset grief
    }
    else
    using (var file = File.Create (parser.Filename))
        await part.CopyToAsync (file) ;
}

This ought to get you started.

Solution 2

I managed to solve my problem (read the multipart that is), but had to move to .NET 4.5 , if anyone knows the changes in order to work in .NET 4.0 (by replacing "await" and "async" with something else I guess) I would love to know. So that's what I did.

  static void Main(string[] args)
  {

            //some code here...

            // POST the request
            var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
            Console.Write(httpResponse.GetResponseStream());
            readMultipart(httpResponse).Wait();
    }

    async static Task readMultipart(HttpWebResponse httpResponse)
    {
         var content = new StreamContent(httpResponse.GetResponseStream());
        content.Headers.Add("Content-Type", httpResponse.ContentType);
        var multipart = await content.ReadAsMultipartAsync();
        String filename = "";
        String json = await multipart.Contents[0].ReadAsStringAsync();
        JObject o = JObject.Parse(json);
        filename = o["fileName"].ToString();
        using (var file = File.Create("C:\\testWS\\" + filename))
            await multipart.Contents[1].CopyToAsync(file);
    }
Share:
11,235
Theodore K.
Author by

Theodore K.

Updated on July 25, 2022

Comments

  • Theodore K.
    Theodore K. over 1 year

    I get a multipart/mixed (with a JSON object and a file) like this, as response when I call a web service:

    "--Boundary_9_15033478_1405613164044\r\n
    
    Content-Type: application/json
    \r\n\r\n{\"docId\":9007492,\"protId\":200,\"protNum\":\"0002084B14\",\"protDate\":\"Wed Jul 16 00:00:00 EEST 2014\",\"categoryId\":1000,\"desc\":\"ѥ񩣱ⷞ ��ƣ䲜��",\"linkNum\":\"ư1\\/00005545\",\"flag1\":\"\",\"flag2\":\"\",\"flag3\":\"\",\"flag4\":\"\",\"stsId\":1,\"stsDesc\":\"WS04: Check Layer I - OK\",\"wsDataList\":[],\"fileName\":\"WsTestToolkitMain.jpg\"}\r\n--Boundary_9_15033478_1405613164044\r\n
    
    Content-Type: application/octet-stream
    \r\n\r\n????\0JFIF\0\0`\0`\0\0??\0C\0\a\a\a\a\a\a\b\t\v\t\b\b\n\b\a\a\n\r\n\n\v\f\f\f
    ...
    ...
    ...
    ??\n?$??\0???????\r\n--Boundary_9_15033478_1405613164044--\r\n"
    

    The way I got it is by getting a Stream of the response (of the HttpWebRequest) and then decode it with UTF-8. This gives me the above String. The question is how can I get the JSON and (more importantly) save the file ?

    I tried changing (because they are for multipart/form-data not multipart/mixed) this and this but I can't get the file, maybe because its Content-Type is application/octet-stream . Here is what doesn't work, file appears as it was damaged/corrupted in windows:

    // Read the stream into a byte array
    byte[] data = ToByteArray(stream);//Source
    string content = encoding.GetString(data);
    int contentLength = content.Length;//Length
    byte[] fileData = new byte[contentLength];//Destination
    Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);
    this.FileContents = fileData;
    File.WriteAllBytes("G:\\" + parser.Filename, parser.FileContents);
    

    UPDATE: Followed the answer by Anton Tykhyy (thanks!) but I'm getting an error when

    var multipart = await content.ReadAsMultipartAsync () ;
    

    Invalid 'HttpContent' instance provided. It does not have a content-type header value. 'HttpContent' instances must have a content-type header starting with 'multipart/'.

    I tried to add this line before

    content.Headers.Add("Content-Type", "multipart/mixed");
    

    but now I'm getting another error (that I don't really understand too)

    Invalid 'HttpContent' instance provided. It does not have a 'multipart' content-type header with a 'boundary' parameter.

    UPDATE 2: Found it, I just had to do this:

        var content = new StreamContent(httpResponse.GetResponseStream());
        content.Headers.Add("Content-Type", httpResponse.ContentType);