Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

multipart

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);
like image 571
Theodore K. Avatar asked Jul 18 '14 08:07

Theodore K.


2 Answers

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.

like image 160
Anton Tykhyy Avatar answered Sep 28 '22 07:09

Anton Tykhyy


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);
    }
like image 32
Theodore K. Avatar answered Sep 28 '22 07:09

Theodore K.