Pubblica i dati del modulo utilizzando HttpWebRequest


91

Voglio inviare alcuni dati del modulo a un URL specificato che non è all'interno della mia applicazione web. Ha lo stesso dominio, come "domain.client.nl". L'applicazione web ha un URL "web.domain.client.nl" e l'URL in cui voglio postare è "idp.domain.client.nl". Ma il mio codice non fa nulla ..... qualcuno sa cosa sto sbagliando?

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


6
Non proprio un duplicato, come l'altro vuole specificamente usare WebClient.

Risposte:


71

Sia il nome del campo che il valore devono essere codificati nell'URL. formato dei dati del post e stringa di query sono gli stessi

Il modo di fare .net è qualcosa del genere

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

Questo si occuperà della codifica dei campi e dei nomi dei valori


10
string postdata = outgoingQueryString.ToString();ti darà una stringa con il valore "System.Collections.Specialized.NameValueCollection".
sfuqua

1
In realtà @sfuqua se decompili il sorgente per HttpUtility (in particolare quello in System.Web) vedrai che restituisce un tipo NameValueCollection specializzato: return (NameValueCollection) new HttpValueCollection (query, false, true, encoding); che converte correttamente la raccolta in una stringa di query. Se usi quello di RestSharp, tuttavia, non ...
The Senator

Interessante, poiché avevo visto questo problema esatto ToString(), anche se ora non ricordo se fosse durante l'utilizzo di RestSharp. Possibilità definitiva. Grazie per la correzione.
sfuqua

Non è stato immediatamente chiaro come outgoingQueryStringfunzionasse come implicito nel codice di esempio. Queste due domande rispondono a: (1) HttpValueCollection e NameValueCollection e (2) Qualsiasi classe .NET che crea una stringa di query con coppie di valori chiave o simili .
Kenny Evitt

56

Prova questo:

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

6
Preferirei scrivere: request.Method = WebRequestMethods.Http.Post;
Totalys

richiesta di controllo Risposta prima dell'uso
Marco Fantasia

@MarcoFantasia Se controlli request.HaveResponsedevi prima ottenere effettivamente la risposta. HttpWebResponse response = (HttpWebResponse) request.GetResponse(); if (request.HaveResponse) { ... }
Sì Barry

40

Stai codificando il modulo in modo errato. Dovresti codificare solo i valori:

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

modificare

Ho sbagliato. Secondo la sezione 8.2.1 RFC1866 sia i nomi che i valori dovrebbero essere codificati.

Ma per l'esempio dato, i nomi non hanno caratteri che devono essere codificati, quindi in questo caso il mio esempio di codice è corretto;)

Il codice nella domanda è ancora errato in quanto codificherebbe il segno di uguale che è il motivo per cui il server web non può decodificarlo.

Un modo più corretto sarebbe stato:

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

Grazie, ma ora ricevo il seguente errore: Il server remoto ha restituito un errore: (412) Precondizione non riuscita.
wsplinter

Io google molto :) Ma l'ho risolto, lo sto facendo in modo sporco. Non faccio una HttpWebRequest ma costruisco un form html all'interno di una String e lo scrivo al browser (nell'onload farò un submit).
wsplinter

3
@wsplinter: aiuterebbe gli altri se si documentasse la soluzione alla precondizione fallita.
jgauffin

@jgauffin: come inserisco i valori dei pulsanti di opzione? Supponiamo che io abbia 3 pulsanti di opzione appartenenti allo stesso gruppo.
Asad Refai

1
Apparentemente, questo non ha funzionato per me abbastanza come previsto poiché UrlEncode cambia simboli come @ in un codice che non veniva accettato nella chiamata API; cambiandolo per utilizzare NameValueCollection come mostrato nella risposta di @ user3389691 funziona perfettamente.
dhruvpatel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.