c# multipart/form-data submit programmatically

14,046

Solution 1

posts os multipart/form-data type have a different structure because they are meant to transfer data and not just plain text.

Here's the format:

--[random number, a GUID is good here]
Content-Disposition: form-data; name="[name of variable]"

[actual value]
--[random number, a GUID is good here]--

Using HTTPWebRequest you can create a request that has that format. Here's a sample:

string boundary = Guid.NewGuid().ToString();
string header = string.Format("--{0}", boundary);
string footer = string.Format("--{0}--", boundary);

StringBuilder contents = new StringBuilder();
contents.AppendLine(header);

contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "username"));
contents.AppendLine();
contents.AppendLine("your_username");

contents.AppendLine(header);
contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "password"));
contents.AppendLine();
contents.AppendLine("your_password");

contents.AppendLine(footer);

Solution 2

Here is an article on multipart form posts in C# with more detail. This code was eventually merged into RestSharp, which is an excellent library you could use to generate the request.

Solution 3

The best way to send multipart form data in C# is shown in the snippet, here you see that adding different type of content is as easy as adding it to the wrapper multipart content type:

var documentContent = new MultipartFormDataContent();
documentContent.Add(new StringContent("AnalyticsPage.xlsx"), "title");
documentContent.Add(new ByteArrayContent(File.ReadAllBytes("C:\\Users\\awasthi\\Downloads\\AnalyticsPage.xlsx")), "file", "AnalyticsPage.xlsx");

Then just make an api call:

using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true, CookieContainer = new CookieContainer() }))
{
  response = client.PostAsync(documentAddApi, documentContent).Result;
  var responseContent = response.Content.ReadAsStringAsync().Result;
 }

Here the expectation is that the rest endpoint you are making a call to is accepting a 'title' field for the file and the byte array of the file named 'file'.

Share:
14,046
Admin
Author by

Admin

Updated on June 09, 2022

Comments

  • Admin
    Admin almost 2 years

    So got an small problem. Im creating an small application to automate an form submission on one website. But the bad thing is that they are using multipart/form-data for that. There is no file uploading just some text fields for submission.

    Of course doing it like this it fails.

    string postData1 = "firstfield="+firststring+"secondfield="+secondstring;

    So my question is how the hell post those form fields with multipart form?

    Posting like arrays in php like this:

    $postdata = array('firstfield' => $firststring, 'secondfield' => $secondstring);

    works and passes the form but seems not working with c#

    Any suggestions?


    Data submission goes through 3 page ( basic screenscrape ) login/part1/part2

    So far i can log in successfully and post part1 (uses normal application/x-www-form-urlencoded form )

    But when ill try to post multipart form it fails and sends me back to part1. So maybe is my code wrong but here it is:

    string password = "password";
    string username = "username";
    string link = "http://somelink.com/";
    string text = "Blah Blah some text here";
    string title = "Blah Blah";
    string tags1 = title;
    string summary = "Blah Blah summary";
    string tags = tags1.Replace(" ", ",");
    
    // Set cookie container
    CookieContainer cookieJar = new CookieContainer();
    
    string loginData = "username=" + username + "&password=" + password + "&processlogin=1&return=%2Fsubmit.php";
    
    HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create("http://loginlink.com/login.php");
    myRequest.Method = "POST";
            myRequest.ServicePoint.Expect100Continue = false;
    myRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 GTB6 (.NET CLR 3.5.30729)";
    myRequest.Timeout = 10000;
    myRequest.ContentType = "application/x-www-form-urlencoded";
    myRequest.ContentLength = loginData.Length;
    myRequest.CookieContainer = cookieJar;
    myRequest.KeepAlive = true;
    myRequest.AllowAutoRedirect = true;
    
    //Write post data to stream
    StreamWriter myWriter = new StreamWriter(myRequest.GetRequestStream());
    myWriter.Write(loginData);
    myWriter.Close();
    
    // Get the response.
    HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
    
    // Open the stream using a StreamReader for easy access.
    StreamReader myReader = new StreamReader(myResponse.GetResponseStream());
    // Read the content.
    string output = myReader.ReadToEnd();
    
    // Clean up the streams and the response.
    myReader.Close();
    myResponse.Close();
    
    
    Match matchkey = Regex.Match(output, "type=\"hidden\" name=\"randkey\" value=\"([^\"]+)\"", RegexOptions.IgnoreCase);
    string key1 = matchkey.Groups[1].Value;
    Match matchid = Regex.Match(output, "type=\"hidden\" name=\"id\" value=\"([^\"]+)\"", RegexOptions.IgnoreCase);
    string id1 = matchid.Groups[1].Value;
    
    
    string postData = "url=" + link + "&phase=1&randkey=" + key1 + "&id=" + id1;
    
    HttpWebRequest myRequest2 = (HttpWebRequest)WebRequest.Create("http://submitpage1.com/submit.php");
    myRequest2.Method = "POST";
    myRequest2.ServicePoint.Expect100Continue = false;
    myRequest2.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 GTB6 (.NET CLR 3.5.30729)";
    myRequest2.Timeout = 10000;
    myRequest2.ContentType = "application/x-www-form-urlencoded";
    myRequest2.ContentLength = postData.Length;
    myRequest2.CookieContainer = cookieJar;
    myRequest2.KeepAlive = true;
    myRequest2.AllowAutoRedirect = true;
    
    
    //Write post data to stream
    StreamWriter myWriter2 = new StreamWriter(myRequest2.GetRequestStream());
    myWriter2.Write(postData);
    myWriter2.Close();
    
    // Get the response.
    HttpWebResponse myResponse2 = (HttpWebResponse)myRequest2.GetResponse();
    
    // Open the stream using a StreamReader for easy access.
    StreamReader myReader2 = new StreamReader(myResponse2.GetResponseStream());
    // Read the content.
    string output1 = myReader2.ReadToEnd();
    
    // Clean up the streams and the response.
    myReader2.Close();
    myResponse2.Close();
    
    Match matchkey1 = Regex.Match(output1, "type=\"hidden\" name=\"randkey\" value=\"([^\"]+)\"", RegexOptions.IgnoreCase);
    string key2 = matchkey1.Groups[1].Value;
    Match matchid1 = Regex.Match(output1, "type=\"hidden\" name=\"randkey\" value=\"([^\"]+)\"", RegexOptions.IgnoreCase);
    string id2 = matchid1.Groups[1].Value;
    
    string boundary = "-----------------------------1721856231228";
    
    // Build up the post
    StringBuilder sb = new StringBuilder();
    sb.Append("\r\n" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"title\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(title);
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"tags\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(tags);
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"bodytext\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(text);
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"summarycheckbox\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append("on");
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"summarytext\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(summary);
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"remLen\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append("125");
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"category\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append("1");
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"trackback\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append("");
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"url\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(link);
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"phase\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append("2");
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"randkey\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(key2);
    sb.Append("\r\n--" + boundary + "\r\n");
    sb.Append("Content-Disposition: form-data; name=\"id\"" + "\r\n");
    sb.Append("\r\n");
    sb.Append(id2);
    sb.Append("\r\n--" + boundary + "--" + "\r\n");
    
    string postData1 = sb.ToString();
    
    HttpWebRequest myRequest3 = (HttpWebRequest)WebRequest.Create("http://submitpage2.com/submit.php");
    myRequest3.Method = "POST";
    myRequest3.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 GTB6 (.NET CLR 3.5.30729)";
    myRequest3.Timeout = 10000;
    myRequest3.ServicePoint.Expect100Continue = false;
    myRequest3.Referer = "http://bookmarkindo.com/submit.php";
    myRequest3.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    myRequest3.ContentType = "multipart/form-data; boundary=" + boundary;
    myRequest3.ContentLength = postData1.Length;
    myRequest3.CookieContainer = cookieJar;
    myRequest3.KeepAlive = true;
    myRequest3.AllowAutoRedirect = true;
    
    //Write out postdata
    StreamWriter myWriter3 = new StreamWriter(myRequest3.GetRequestStream());
    myWriter3.Write(postData1);
    myWriter3.Close();
    
    // Get the response.
    HttpWebResponse myResponse3 = (HttpWebResponse)myRequest3.GetResponse();
    
    // Open the stream using a StreamReader for easy access.
    StreamReader myReader3 = new StreamReader(myResponse3.GetResponseStream());
    // Read the content.
    string output2 = myReader3.ReadToEnd();
    
    // Clean up the streams and the response.
    myReader3.Close();
    myResponse3.Close();
    

    All suggestions are welcome