4

I am trying to upload an image programmatically via an API to another server. The API expects me to upload image in a byte array to be sent in a field: "image_content".

My implementation and calling code is as below. The web request hits the server but the server responds that the image is not present in my web request.

When I run the below code, I am getting error that the image is not present in the request. What am I missing here?

public static class FormUpload
{
    private static readonly Encoding encoding = Encoding.UTF8;
    public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters)
    {
        string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
        string contentType = "multipart/form-data; boundary=" + formDataBoundary;

    byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);

    return PostForm(postUrl, userAgent, contentType, formData);
}
private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData)
{
    HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;

    if (request == null)
    {
        throw new NullReferenceException("request is not a http request");
    }

    // Set up the request properties.
    request.Method = "POST";
    request.ContentType = contentType;
    request.UserAgent = userAgent;
    request.ContentLength = formData.Length;


    // Send the form data to the request.
    using (Stream requestStream = request.GetRequestStream())
    {
        requestStream.Write(formData, 0, formData.Length);
        requestStream.Close();
    }

    return request.GetResponse() as HttpWebResponse;
}

private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
{
    Stream formDataStream = new System.IO.MemoryStream();
    bool needsCLRF = false;

    foreach (var param in postParameters)
    { 
        if (param.Value is FileParameter)
        {
            FileParameter fileToUpload = (FileParameter)param.Value;

            // Add just the first part of this param, since we will write the file data directly to the Stream
            string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
                boundary,
                param.Key,
                fileToUpload.FileName ?? param.Key,
                fileToUpload.ContentType ?? "application/octet-stream");

            formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));

            // Write the file data directly to the Stream, rather than serializing it to a string.
            formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
        }
        else
        {
            string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
                boundary,
                param.Key,
                param.Value);
            formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
        }
    }

    // Add the end of the request.  Start with a newline
    string footer = "\r\n--" + boundary + "--\r\n";
    formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));

    // Dump the Stream into a byte[]
    formDataStream.Position = 0;
    byte[] formData = new byte[formDataStream.Length];
    formDataStream.Read(formData, 0, formData.Length);
    formDataStream.Close();

    return formData;
}

public class FileParameter
{
    public byte[] File { get; set; }
    public string FileName { get; set; }
    public string ContentType { get; set; }
    public FileParameter(byte[] file) : this(file, null) { }
    public FileParameter(byte[] file, string filename) : this(file, filename, null) { }
    public FileParameter(byte[] file, string filename, string contenttype)
    {
        File = file;
        FileName = filename;
        ContentType = contenttype;
    }
}

}

The code to call above function is:

// Read file data
FileStream fs = new FileStream("c:\\myimage.jpeg", FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
fs.Close();

// Generate post objects
Dictionary<string, object> postParameters = new Dictionary<string, object>();
postParameters.Add("image_content",data);

// Create request and receive response
string postURL = "myurl";
string userAgent = "Mozilla";
HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(postURL, userAgent, postParameters);

// Process response
StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());
string fullResponse = responseReader.ReadToEnd();
webResponse.Close();
Response.Write(fullResponse);
9
  • 1
    read this stackoverflow.com/questions/1131425/… Commented Oct 30, 2014 at 8:06
  • Did you try using WebReq.ContentType = "image/jpeg"; ? Commented Oct 30, 2014 at 8:20
  • @Mez, Yes. I tried it. Commented Oct 30, 2014 at 8:42
  • Check this link out dreamincode.net/forums/topic/… Commented Oct 30, 2014 at 10:51
  • @Mez, the link you have mentioned doesn't have a solution. Commented Oct 31, 2014 at 10:00

3 Answers 3

3

In my opinion, you should use the MultipartFormDataContent class because it "Provides a container for content encoded using multipart/form-data MIME type.". Try this

    public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, byte[] data)
    {
        string contentType;
        byte[] formData = Program.GetMultipartFormData(data, out contentType);  
        return PostForm(postUrl, userAgent, contentType, formData);
    }

    public static byte[] GetMultipartFormData(byte[] data, out string contentType)
    {
        var byteArrayContent = new ByteArrayContent(data);
        byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
        byteArrayContent.Headers.Add("image_content", "myimage.jpeg");

        var content = new MultipartFormDataContent(String.Format("----------{0:N}", Guid.NewGuid())) { byteArrayContent };
        contentType = content.Headers.ContentType.ToString();

        return content.ReadAsByteArrayAsync().Result;
    }
Sign up to request clarification or add additional context in comments.

Comments

2

I was able to resolve the problem by the use of RestSharp Api mentioned in the stackoverflow question Upload file through c# using JSON request and RestSharp.

Comments

1

You all code is fine but you forgot To encode you parameter

try this

string postData = string.Format("--{0}\r\nContent-Disposition: 
form-data; name=\"{1}\"\r\n\r\n{2}",
                boundary,
                HttpUtility.UrlEncode(param.Key),
                HttpUtility.UrlEncode(param.Value));

In case of binary data

HttpUtility.UrlEncode(Convert.ToBase64String(byte[]))

try to use this code to add parameter in your request

NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("uname", "username");
outgoingQueryString.Add("pname", "password");
string postdata = outgoingQueryString.ToString();

and write this postdata in you request

Comments

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.