Publier les données du formulaire à l'aide de HttpWebRequest

91

Je souhaite publier des données de formulaire sur une URL spécifiée qui ne se trouve pas dans ma propre application Web. Il a le même domaine, tel que "domain.client.nl". L'application Web a une url "web.domain.client.nl" et l'url sur laquelle je souhaite publier est "idp.domain.client.nl". Mais mon code ne fait rien ..... est-ce que quelqu'un sait ce que je fais mal?

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
la source
Double possible: stackoverflow.com/questions/5401501/…
Dariusz
6
Pas tout à fait un double, comme l'autre veut spécifiquement utiliser WebClient.

Réponses:

71

Le nom du champ et la valeur doivent être encodés en URL. le format des données de publication et la chaîne de requête sont identiques

La façon de faire .net est quelque chose comme ça

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

Cela prendra soin d'encoder les champs et les noms de valeur

user3389691
la source
10
string postdata = outgoingQueryString.ToString();vous donnera une chaîne avec la valeur "System.Collections.Specialized.NameValueCollection".
sfuqua
1
En fait @sfuqua si vous décompilez la source de HttpUtility (en particulier celle de System.Web), vous verrez qu'elle renvoie un type de NameValueCollection spécialisé: return (NameValueCollection) new HttpValueCollection (query, false, true, encoding); qui convertit correctement la collection en chaîne de requête. Si vous utilisez celui de RestSharp cependant, il ne ...
The Senator
Intéressant, car j'avais vu exactement ce problème avec ToString(), même si je ne me souviens pas maintenant si c'était en utilisant RestSharp. Possibilité définie. Merci pour la correction.
sfuqua
Il n'était pas immédiatement clair comment outgoingQueryStringfonctionnait comme le suggère l'exemple de code. Ces deux questions répondent que - (1) HttpValueCollection et NameValueCollection et (2) Toute classe .NET qui crée une chaîne de requête à partir de paires clé-valeur ou similaires .
Kenny Evitt
56

Essaye ça:

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
la source
6
Je préfère écrire: request.Method = WebRequestMethods.Http.Post;
Totalys le
check request.HaveResponse before use response
Marco Fantasia
@MarcoFantasia Si vous cochez, request.HaveResponsevous devez d'abord obtenir la réponse. HttpWebResponse response = (HttpWebResponse) request.GetResponse(); if (request.HaveResponse) { ... }
Oui Barry
40

Vous encodez le formulaire de manière incorrecte. Vous ne devez encoder que les valeurs:

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

Éditer

J'avais tort. Conformément à la section 8.2.1 de la RFC1866, les noms et les valeurs doivent être codés.

Mais pour l'exemple donné, les noms n'ont aucun caractère à encoder, donc dans ce cas mon exemple de code est correct;)

Le code de la question est toujours incorrect car il encoderait le signe égal qui est la raison pour laquelle le serveur Web ne peut pas le décoder.

Une manière plus appropriée aurait été:

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
la source
Merci, mais maintenant j'obtiens l'erreur suivante: Le serveur distant a renvoyé une erreur: (412) Precondition Failed.
wsplinter
Je cherche beaucoup sur Google :) Mais je l'ai réparé, je le fais de façon désordonnée. Je ne fais pas de HttpWebRequest mais je construis un formulaire html à l'intérieur d'une chaîne et je le wirte au navigateur (dans le téléchargement, je vais faire un envoi).
wsplinter
3
@wsplinter: Cela aiderait les autres si vous documentiez la solution à l'échec de la préconditionnement.
jgauffin
@jgauffin: Comment publier des valeurs de bouton radio? Supposons que j'ai 3 boutons radio appartenant au même groupe.
Asad Refai
1
Apparemment, cela n'a pas fonctionné pour moi tout à fait comme prévu car UrlEncode change les symboles comme @ en un code qui n'était pas accepté dans l'appel d'API; le changer pour utiliser NameValueCollection comme showin dans la réponse de @ user3389691 fonctionne parfaitement.
dhruvpatel