26

I'm trying to send some images + some meta data to a server by HTTP post from a windows store app but get stuck when trying to actually include the data in the post. It cannot be done the way you would accomplish this in a windows forms app or similar due to the changes to the store app API.

I get the error.

cannot convert source type byte[] to target type System.Net.Http.httpContent

now this is obviously because it's 2 different types that can't be implicitly casted, but it's basically what I'm looking to be able to do. How do I make get my byte array data into the httpContent type so I can include it in the following call

httpClient.PostAsync(Uri uri,HttpContent content);

here's my full upload method:

async private Task UploadPhotos(List<Photo> photoCollection, string recipient, string format)
    {
        PhotoDataGroupDTO photoGroupDTO = PhotoSessionMapper.Map(photoCollection);

        try
        {
            var client = new HttpClient();
            client.MaxResponseContentBufferSize = 256000;
            client.DefaultRequestHeaders.Add("Upload", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");

            // POST action_begin
            const string actionBeginUri = "http://localhost:51139/PhotoService.axd?action=Begin";
            HttpResponseMessage response = await client.GetAsync(actionBeginUri);
            response.EnsureSuccessStatusCode();
            string responseBodyAsText = await response.Content.ReadAsStringAsync();
            string id = responseBodyAsText;
            ////

            // POST action_upload
            Uri actionUploadUri = new Uri("http://localhost:51139/PhotoService.axd?action=Upload&brand={0}&id={1}&name={2}.jpg");

            var metaData = new Dictionary<string, string>()
            {
                {"Id", id},
                {"Brand", "M3rror"}, //TODO: Denne tekst skal komme fra en konfigurationsfil.
                {"Format", format},
                {"Recipient", recipient}
            };

            string stringData = "";
            foreach (string key in metaData.Keys)
            {
                string value;
                metaData.TryGetValue(key, out value);
                stringData += key + "=" + value + ",";
            }

            UTF8Encoding encoding = new UTF8Encoding();
            byte[] byteData = encoding.GetBytes(stringData);

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, actionUploadUri);

            // send meta data
            // TODO get byte data in as content
            HttpContent metaDataContent = byteData;
            HttpResponseMessage actionUploadResponse = await client.PostAsync(actionUploadUri, metaDataContent);

            actionUploadResponse.EnsureSuccessStatusCode();
            responseBodyAsText = await actionUploadResponse.Content.ReadAsStringAsync();

            // send photos
            // TODO get byte data in as content
            foreach (byte[] imageData in photoGroupDTO.PhotosData)
            {
                HttpContent imageContent = imageData;
                actionUploadResponse = await client.PostAsync(actionUploadUri, imageContent);
                actionUploadResponse.EnsureSuccessStatusCode();
                responseBodyAsText = await actionUploadResponse.Content.ReadAsStringAsync();
            }                
            ////

            // POST action_complete
            const string actionCompleteUri = "http://localhost:51139/PhotoService.axd?action=Complete";
            HttpResponseMessage actionCompleteResponse = await client.GetAsync(actionCompleteUri);
            actionCompleteResponse.EnsureSuccessStatusCode();
            responseBodyAsText = await actionCompleteResponse.Content.ReadAsStringAsync();
            ////
        }

        catch (HttpRequestException e)
        {
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.ToString());
        }
    }
1
  • 1
    Doesn't the binary data need to be serialised? Also you probably want to stream it rather than upload it all at once. stackoverflow.com/questions/19005991/… may help. Commented May 7, 2014 at 13:21

3 Answers 3

67

It will be more straightforward to use System.Net.Http.ByteArrayContent. E.g:

// Converting byte[] into System.Net.Http.HttpContent.
byte[] data = new byte[] { 1, 2, 3, 4, 5};
ByteArrayContent byteContent = new ByteArrayContent(data);
HttpResponseMessage response = await client.PostAsync(uri, byteContent);

For text only with an specific text encoding use:

// Convert string into System.Net.Http.HttpContent using UTF-8 encoding.
StringContent stringContent = new StringContent(
    "blah blah",
    System.Text.Encoding.UTF8);
HttpResponseMessage response = await client.PostAsync(uri, stringContent);

Or as you mentioned above, for text and images using multipart/form-data:

// Send binary data and string data in a single request.
MultipartFormDataContent multipartContent = new MultipartFormDataContent();
multipartContent.Add(byteContent);
multipartContent.Add(stringContent);
HttpResponseMessage response = await client.PostAsync(uri, multipartContent);
Sign up to request clarification or add additional context in comments.

2 Comments

Which is fast enough, secure to process the data which contains the text and numbers combination (around 1lakh records in a list-json serialized)? ByteArrayContent or StringContent. Please suggest
I think the variable name above should be "response" not "reponse", I was unable to edit it. Caused me issues for a few minutes when copying / pasting into existing code, might save someone else some time if the code is updated with the correct spelling?
12

You need to wrap the byte array in an HttpContent type.

If you are using System,Net.Http.HttpClient:

HttpContent metaDataContent = new ByteArrayContent(byteData);

If you are using the preferred Windows.Web.Http.HttpClient:

Stream stream = new MemoryStream(byteData);
HttpContent metaDataContent = new HttpStreamContent(stream.AsInputStream());

2 Comments

What should be the server-side action pattern for accepting a ByteArrayContent?
In my case, I'm processing a file uploaded on the server in order to send it to another server's REST API. The use of ByteArrayContent doesn't work. The REST server just gives a status 200 empty reply. However, if I write the uploaded data to a file on the disk and then use the file for a StreamContent, it works. I wonder why.
1

The concept you are looking for is called Serialization. Serialization means preparing your data (which could be heterogeneous and without a predefined strucutre) for storage or transmission. Then, when you need to use the data again, you do the opposite operation, deserialization, and get back the original data structure. The link above shows a few methods on how this could be done in C#.

1 Comment

Nice hint, thanks. Following one answer elsewhere I was decoding form content using UTF-8. Turns out it was being sent as Base64, so that's what I needed to use.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.