Veröffentlichen Sie Formulardaten mit HttpWebRequest

90

Ich möchte einige Formulardaten an eine angegebene URL senden, die sich nicht in meiner eigenen Webanwendung befindet. Es hat dieselbe Domain wie "domain.client.nl". Die Webanwendung hat eine URL "web.domain.client.nl". Die URL, unter der ich posten möchte, lautet "idp.domain.client.nl". Aber mein Code macht nichts ..... weiß jemand, was ich falsch mache?

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
quelle
Mögliches Duplikat: stackoverflow.com/questions/5401501/…
Dariusz
6
Nicht ganz ein Duplikat, wie der andere speziell verwenden möchte WebClient.

Antworten:

71

Sowohl der Feldname als auch der Wert sollten url-codiert sein. Format der Postdaten und Abfragezeichenfolge sind identisch

Die .net-Methode ist ungefähr so

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

Dadurch werden die Felder und die Wertnamen codiert

user3389691
quelle
10
string postdata = outgoingQueryString.ToString();gibt Ihnen eine Zeichenfolge mit dem Wert "System.Collections.Specialized.NameValueCollection".
Sfuqua
1
@Sfuqua Wenn Sie die Quelle für HttpUtility dekompilieren (insbesondere die in System.Web), werden Sie feststellen, dass sie einen speziellen NameValueCollection-Typ zurückgibt: return (NameValueCollection) new HttpValueCollection (query, false, true, encoding); Dadurch wird die Sammlung korrekt in eine Abfragezeichenfolge konvertiert. Wenn Sie jedoch die von RestSharp verwenden, funktioniert dies nicht ...
The Senator
Interessant, da ich genau dieses Problem gesehen hatte ToString(), obwohl ich mich jetzt nicht erinnern kann, ob es während der Verwendung von RestSharp war. Bestimmte Möglichkeit. Danke für die Korrektur.
Sfuqua
Es war nicht sofort klar, wie outgoingQueryStringder Beispielcode funktioniert. Diese beiden Fragen beantworten Folgendes: (1) HttpValueCollection und NameValueCollection und (2) Jede .NET-Klasse, die eine Abfragezeichenfolge mit Schlüsselwertpaaren oder dergleichen erstellt .
Kenny Evitt
56

Versuche dies:

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();
Parisa Shamsaie
quelle
6
Ich würde lieber schreiben: request.Method = WebRequestMethods.Http.Post;
Totalys
check request.HaveResponse vor Gebrauch Antwort
Marco Fantasia
@MarcoFantasia Wenn Sie überprüfen request.HaveResponseSie tatsächlich bekommen zuerst die Antwort. HttpWebResponse response = (HttpWebResponse) request.GetResponse(); if (request.HaveResponse) { ... }
Ja, Barry,
40

Sie codieren das Formular falsch. Sie sollten nur die Werte codieren:

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));

bearbeiten

Ich habe mich geirrt Gemäß RFC1866 Abschnitt 8.2.1 sollten sowohl Namen als auch Werte codiert werden.

Für das angegebene Beispiel haben die Namen jedoch keine Zeichen, die codiert werden müssen. In diesem Fall ist mein Codebeispiel also korrekt;)

Der Code in der Frage ist immer noch falsch, da er das Gleichheitszeichen codieren würde. Dies ist der Grund, warum der Webserver es nicht decodieren kann.

Ein richtigerer Weg wäre gewesen:

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));
}
jgauffin
quelle
Vielen Dank, aber jetzt wird der folgende Fehler angezeigt: Der Remote-Server hat einen Fehler zurückgegeben: (412) Voraussetzung fehlgeschlagen.
wsplinter
Ich google viel :) Aber ich habe es behoben, ich mache es auf einem schmutzigen Weg. Ich mache keine HttpWebRequest, aber ich erstelle ein HTML-Formular in einem String und schicke es an den Browser (im Onload mache ich eine Übermittlung).
wsplinter
3
@wsplinter: Es würde anderen helfen, wenn Sie dokumentieren, dass die Lösung für die Vorbedingung fehlgeschlagen ist.
Jgauffin
@jgauffin: Wie poste ich Optionsfeldwerte? Angenommen, ich habe 3 Optionsfelder, die zur selben Gruppe gehören.
Asad Refai
1
Anscheinend hat dies bei mir nicht ganz wie erwartet funktioniert, da UrlEncode Symbole wie @ in einen Code ändert, der beim API-Aufruf nicht akzeptiert wurde. Das Ändern, um NameValueCollection als Showin in der Antwort von @ user3389691 zu verwenden, funktioniert perfekt.
Dhruvpatel