18

I am trying to use the ImageShack API to upload images. To use it, I am supposed to POST the image using multipart/form-data. I did it like ...

var postData = "";
var req = HttpWebRequest.Create("http://www.imageshack.us/upload_api.php");
req.Method = "POST";
req.ContentType = "multipart/form-data";
postData += "key=my_key_here&";
postData += "type=base64&";

// get base64 data from image
byte[] bytes = File.ReadAllBytes(@"D:\tmp\WpfApplication1\WpfApplication1\Images\Icon128.gif");
string encoded = Convert.ToBase64String(bytes);
postData += "fileupload=" + encoded;

byte[] reqData = Encoding.UTF8.GetBytes(postData);
using (Stream dataStream = req.GetRequestStream())
{
    dataStream.Write(reqData, 0, reqData.Length);
}

var res = (HttpWebResponse)req.GetResponse();
var resStream = res.GetResponseStream();
var reader = new StreamReader(resStream);
string resString = reader.ReadToEnd();
txt1.Text = resString;

but ImageShack is complaining that

<links>
    <error id="parameter_missing">Sorry, but we've detected that unexpected data is received. Required parameter 'fileupload' is missing or your post is not multipart/form-data</error>
</links>

FileUpload is present and I am using multipart/form-data whats wrong?

UPDATE:

New Code http://pastebin.com/TN6e0CD8

Post data http://pastebin.com/fYE9fsxs

UPDATE 2

i looked at the other question Multipart forms from C# client. modified my code with boundary, removed the expect 100 header still i cant get it working ...

ServicePointManager.Expect100Continue = false;
var boundary = "-----------------------------28520690214962";
var newLine = Environment.NewLine;
var propFormat = boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine + newLine;
var fileHeaderFormat = boundary + newLine +
                        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + newLine;

var req = (HttpWebRequest)HttpWebRequest.Create("http://jm/php/upload.php");
req.Method = WebRequestMethods.Http.Post;
req.ContentType = "multipart/form-data; boundary=" + boundary;

using (var reqStream = req.GetRequestStream()) {
    var reqWriter = new StreamWriter(reqStream);
    var tmp = string.Format(propFormat, "str1", "hello world");
    reqWriter.Write(tmp);
    tmp = string.Format(propFormat, "str2", "hello world 2");
    reqWriter.Write(tmp);
    reqWriter.Write(boundary + "--");
    reqWriter.Flush();
}
var res = req.GetResponse();
using (var resStream = res.GetResponseStream()) {
    var reader = new StreamReader(resStream);
    txt1.Text = reader.ReadToEnd();
}
1

3 Answers 3

13

I finally got it with the following code ...

var boundary = "------------------------" + DateTime.Now.Ticks;
var newLine = Environment.NewLine;
var propFormat = "--" + boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine;
var fileHeaderFormat = "--" + boundary + newLine +
                        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + newLine;

var req = (HttpWebRequest)HttpWebRequest.Create("http://jm/php/upload.php");
req.Method = WebRequestMethods.Http.Post;
req.ContentType = "multipart/form-data; boundary=" + boundary;

using (var reqStream = req.GetRequestStream()) {
    var reqWriter = new StreamWriter(reqStream);
    var tmp = string.Format(propFormat, "str1", "hello world");
    reqWriter.Write(tmp);
    tmp = string.Format(propFormat, "str2", "hello world 2");
    reqWriter.Write(tmp);
    reqWriter.Write("--" + boundary + "--");
    reqWriter.Flush();
}
var res = req.GetResponse();
using (var resStream = res.GetResponseStream()) {
    var reader = new StreamReader(resStream);
    txt1.Text = reader.ReadToEnd();
}

Notice boundaries have to begin with -- {boundary declared in ContentType} and ending boundary must begin & end with -- . in my case, I originally used

var propFormat = boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine;

replace it with

var propFormat = "--" + boundary + newLine +
                    "Content-Disposition: form-data; name=\"{0}\"" + newLine + newLine + 
                    "{1}" + newLine;

and everything works

Sign up to request clarification or add additional context in comments.

3 Comments

I don't see where you use the fileHeaderFormat or where you add the file content. Can you add that as well?
requestWriter.Write(string.Format(fileHeaderFormat, "image", myImage.FileName, myImage.ContentType)); requestWriter.Flush(); requestStream.Write(myImageAsByteArray, 0, (myImageAsByteArray.Length); So you write strings to the request with requestWriter but then just write your byte[] directly.
@user2102611 reqWriter and reqStream, in this case. Not bad, but fileHeaderFormat only has 2 params and is a little simplistic - have to ensure they have the file bytes, too: byte[] docBytes; using (FileStream fs = File.OpenRead(@"C:\myPic.jpg") { docBytes = new byte[fs.Length]; using (BinaryReader br = new BinaryReader(fs)) { docBytes = br.ReadBytes((int)fs.Length); } } if (docBytes != null) reqStream.Write(docBytes, 0, docBytes.Length);
12

I believe that you are not building the request body correctly. First, you need to include part boundary (random text) in content type header. For example,

Content-Type: multipart/form-data; boundary=----WebKitFormBoundarySkAQdHysJKel8YBM

Now format of request body will be something like

------WebKitFormBoundarySkAQdHysJKel8YBM 
Content-Disposition: form-data;name="key"

KeyValueGoesHere
------WebKitFormBoundarySkAQdHysJKel8YBM 
Content-Disposition: form-data;name="param2"

ValueHere
------WebKitFormBoundarySkAQdHysJKel8YBM 
Content-Disposition: form-data;name="fileUpload"; filename="y1.jpg"
Content-Type: image/jpeg 

[image data goes here]

I will suggest you to use tool such as Fiddler to understand how these requests are built.

1 Comment

I am not sure if i still missed out anything but with my request data like shown @pastebin full code also on pastebin. I still get the same error
0

This is nothing like multipart/form-data

  1. There's no boundaries between fields (needed even with one field).
  2. Why are you base-64 encoding?
  3. There's no indication of the content-type of the image.

Take a look at RFC 2388 for the actual format spec. It can also be useful to look at a Fiddler grab of a file upload from a web-page.

5 Comments

Yes, VinayC highlighted that to me. I edited the code and it looks like @pastebin now. And the generated post data looks like ... @pastebin
There's no need for the subsequent newlines after the values. Is base-64ing a requirement specific to the API? That's unusual, but I could see how an API might ask for it. Since the base-64ing is not part of the multiform format, what you are sending is not image/gif but text/plain. Beyond that, as long as the newlines are CRLFs it looks correct. I'd recommend not ending the boundary names with ----- as it makes it harder to check that the final one is the same but with an extra --
How do i send the image over? I used base64 after I saw it used somewhere. So maybe I am doing it wrong
@jiewmeng, if you say content-type is image/gif then you can take images bytes and write them directly into the response stream. If API demands it to be in base64 encoded then content type cannot be image/gif but rather text/plain.
hmm, did I make any other mistakes? I tried posting to a PHP script (localhost) and I don't seem to have any $_POST or $_FILE data

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.