99

I want to post some form data to a specified URL that isn't inside my own web application. It has the same domain, such like "domain.client.nl". The web application has a url "web.domain.client.nl" en the url where I want to post to is "idp.domain.client.nl". But my code does nothing..... does someone knows what I'm doing wrong?

Wouter

StringBuilder postData = new StringBuilder();
postData.Append(HttpUtility.UrlEncode(String.Format("username={0}&", uname)));
postData.Append(HttpUtility.UrlEncode(String.Format("password={0}&", pword)));
postData.Append(HttpUtility.UrlEncode(String.Format("url_success={0}&", urlSuccess)));
postData.Append(HttpUtility.UrlEncode(String.Format("url_failed={0}", urlFailed)));

ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = ascii.GetBytes(postData.ToString());

// set up request object
HttpWebRequest request;
try
{
    request = (HttpWebRequest)HttpWebRequest.Create(WebSiteConstants.UrlIdp);
}
catch (UriFormatException)
{
    request = null;
}
if (request == null)
    throw new ApplicationException("Invalid URL: " + WebSiteConstants.UrlIdp);

request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

// add post data to request
Stream postStream = request.GetRequestStream();
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Flush();
postStream.Close();
wsplinter
  • 1,021
  • 1
  • 7
  • 7
  • Possible duplicate: http://stackoverflow.com/questions/5401501/how-to-post-data-to-specific-url-using-webclient-in-c-sharp – Dariusz Feb 05 '13 at 08:22
  • 6
    Not quite a duplicate, as the other specifically wants to use `WebClient`. –  Jul 22 '14 at 00:37

5 Answers5

76

Both the field name and the value should be url encoded. format of the post data and query string are the same

The .net way of doing is something like this

NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("field1","value1");
outgoingQueryString.Add("field2", "value2");
string postdata = outgoingQueryString.ToString();

This will take care of encoding the fields and the value names

user3389691
  • 785
  • 5
  • 2
  • 11
    `string postdata = outgoingQueryString.ToString();` will give you a string with the value `"System.Collections.Specialized.NameValueCollection"`. – sfuqua Jan 27 '16 at 02:49
  • 2
    Actually @sfuqua if you decompile the source for HttpUtility (specifically the one in System.Web) you'll see that it returns a specialized NameValueCollection type: return (NameValueCollection) new HttpValueCollection(query, false, true, encoding); which correctly converts the collection to a query string. If you use the one from RestSharp however, it doesn't... – The Senator Apr 25 '16 at 12:44
  • Interesting, as I had seen this exact problem with `ToString()`, though I cannot now remember if it was while using RestSharp. Definite possibility. Thanks for the correction. – sfuqua Apr 25 '16 at 16:39
  • It wasn't immediately clear how `outgoingQueryString` was working as implied by the example code. These two questions answer that – (1) [HttpValueCollection and NameValueCollection](http://stackoverflow.com/questions/7514461/httpvaluecollection-and-namevaluecollection) and (2) [Any .NET class that makes a query string given key value pairs or the like](http://stackoverflow.com/questions/19653580/any-net-class-that-makes-a-query-string-given-key-value-pairs-or-the-like). – Kenny Evitt Nov 28 '16 at 21:01
67

Try this:

var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");

var postData = "thing1=hello";
    postData += "&thing2=world";
var data = Encoding.ASCII.GetBytes(postData);

request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;

using (var stream = request.GetRequestStream())
{
    stream.Write(data, 0, data.Length);
}

var response = (HttpWebResponse)request.GetResponse();

var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
CharithJ
  • 46,289
  • 20
  • 116
  • 131
Parisa Shamsaie
  • 725
  • 5
  • 3
45

You are encoding the form incorrectly. You should only encode the values:

StringBuilder postData = new StringBuilder();
postData.Append("username=" + HttpUtility.UrlEncode(uname) + "&");
postData.Append("password=" + HttpUtility.UrlEncode(pword) + "&");
postData.Append("url_success=" + HttpUtility.UrlEncode(urlSuccess) + "&");
postData.Append("url_failed=" + HttpUtility.UrlEncode(urlFailed));

edit

I was incorrect. According to RFC1866 section 8.2.1 both names and values should be encoded.

But for the given example, the names do not have any characters that needs to be encoded, so in this case my code example is correct ;)

The code in the question is still incorrect as it would encode the equal sign which is the reason to why the web server cannot decode it.

A more proper way would have been:

StringBuilder postData = new StringBuilder();
postData.AppendUrlEncoded("username", uname);
postData.AppendUrlEncoded("password", pword);
postData.AppendUrlEncoded("url_success", urlSuccess);
postData.AppendUrlEncoded("url_failed", urlFailed);

//in an extension class
public static void AppendUrlEncoded(this StringBuilder sb, string name, string value)
{
    if (sb.Length != 0)
        sb.Append("&");
    sb.Append(HttpUtility.UrlEncode(name));
    sb.Append("=");
    sb.Append(HttpUtility.UrlEncode(value));
}
Community
  • 1
  • 1
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • Thanks, butnow I'm getting the following error: The remote server returned an error: (412) Precondition Failed. – wsplinter Feb 05 '13 at 09:04
  • 1
    I google a lot :) But I fixed it, I'm doing it on a dirtry way. I do not a HttpWebRequest but I build a html form inside a String and wirte it to the browser (in the onload I'll do a submit). – wsplinter Feb 05 '13 at 13:43
  • 3
    @wsplinter: It would help others if you document the solution to precondition failed. – jgauffin Jul 02 '14 at 06:04
  • @jgauffin : How do I post radio button values? Assume I have 3 radio buttons belonging to same group. – Asad Refai Aug 04 '15 at 09:23
  • 1
    Apparently, this didn't work for me quite as expected since UrlEncode changes symbols like @ to a code that was not being accepted in API call; changing it to use NameValueCollection as showin in @user3389691's answer works perfect. – dhruvpatel May 09 '16 at 20:04
0

Use this code:

internal void SomeFunction() {
    Dictionary<string, string> formField = new Dictionary<string, string>();
    
    formField.Add("Name", "Henry");
    formField.Add("Age", "21");
    
    string body = GetBodyStringFromDictionary(formField);
    // output : Name=Henry&Age=21
}

internal string GetBodyStringFromDictionary(Dictionary<string, string> formField)
{
    string body = string.Empty;
    foreach (var pair in formField)
    {
        body += $"{pair.Key}={pair.Value}&";   
    }

    // delete last "&"
    body = body.Substring(0, body.Length - 1);

    return body;
}
Max Lee
  • 241
  • 1
  • 5
  • 14
0
List<KeyValuePair<string, string>> formField= new List<KeyValuePair<string,string>>();

formField.Add(new KeyValuePair<string, string>("Name", "Henry"));
formField.Add(new KeyValuePair<string, string>("Age", "21"));

var body = string.Join("&", formField.Select(kvp => $"{kvp.Key}={kvp.Value}"));
JAKE
  • 1
  • 3