2009-12-14 5 views
3

J'essaie de faire un POST Http à un serveur web Apache.C# - HttpWebRequest - POST

Je trouve que le paramètre ContentLength semble être requis pour que la demande fonctionne. Je préférerais créer un XmlWriter directement à partir de GetRequestStream() et définir SendChunked sur true, mais la requête se bloque indéfiniment à ce moment-là.

Voici comment ma demande est créée:

private HttpWebRequest MakeRequest(string url, string method) 
    { 
     HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest; 
     request.Method = method; 
     request.Timeout = Timeout; //Property in my class, assume it's 10000 
     request.ContentType = "text/xml"; //I am only writing xml with XmlWriter 
     if (method != WebRequestMethods.Http.Get) 
     { 
      request.SendChunked = true; 
     } 
     return request; 
    } 

Comment puis-je faire le travail SendChunked donc je ne dois pas mettre ContentLength? Je ne vois pas de raison de stocker la chaîne de XmlWriter quelque part avant de l'envoyer au serveur.

EDIT: Voici mon code l'origine du problème:

using (Stream stream = webRequest.GetRequestStream()) 
    { 
     using (XmlWriter writer = XmlWriter.Create(stream, XmlTags.Settings)) 
     { 
      Generator.WriteXml<TRequest>(request, writer); 
     } 
    } 

Avant que je n'a pas eu d'utiliser sur l'objet Stream retour de GetRequestStream(), je supposais XmlWriter fermé le courant quand il est disposé, mais c'est pas le cas.

L'une des réponses ci-dessous, laissez-moi y aller. Je vais les marquer comme la réponse.

En ce qui concerne HttpWebRequest, mon code d'origine fonctionne très bien.

+0

-t-il contre un autre serveur web fonctionne (non apache)? Et fermez-vous votre flux à travers le XmlWriter ou le RequestStream? –

+0

Je n'ai pas de serveur Windows pour l'essayer, et j'ai dû passer du temps à écrire du code C# pour lire le message. J'ai envie de peaufiner un paramètre sur HttpWebRequest devrait corriger cela. – jonathanpeppers

Répondre

3

Cela devrait fonctionner comme vous l'avez écrit. Pouvons-nous voir le code qui fait le téléchargement? Vous souvenez-vous de fermer le flux?

+0

Mon XmlWriter est dans un bloc using, et il écrit simplement quelques éléments et attributs avec une certaine boucle. Il appelle WriteEndDocument pour terminer le document. Je commence à me demander si c'est le serveur et pas .Net, mais je n'ai pas de serveur Windows à tester, bien que la version d'Apache soit assez récente. – jonathanpeppers

+0

'WriteEndDocument' ne ferme pas réellement le flux. Quelque part dans votre code, vous appelez 'GetRequestStream' (ou' BeginGetRequestStream'); Une fois que vous avez fini d'écrire votre XML, vous devez appeler la méthode 'Close' sur cette instance' Stream'.Si vous ne le faites pas, il ne saura pas quand vous avez terminé le téléchargement et la connexion restera ouverte pour toujours. – Aaronaught

+0

Vous "utilisez" le 'XmlWriter', qui disposera le' XmlWriter' et seulement le 'XmlWriter'. C'est le ** Stream ** que vous devez appeler 'Dispose' sur (ou' Close', qui est la méthode recommandée). 'XmlWriter' ne le fera pas pour vous. – Aaronaught

1

En regardant l'exemple à http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.sendchunked.aspx, ils définissent toujours une longueur de contenu. En fin de compte, si vous envoyez des données, vous devez indiquer au destinataire le nombre de données que vous allez envoyer. Pourquoi ne savez-vous pas combien de données vous envoyez avant d'envoyer la demande?

ContentLength:

Propriété Valeur Type: System .. ::. Int64 Le nombre d'octets de données à envoyer à la ressource Internet. La valeur par défaut est -1, ce qui indique que la propriété n'a pas été définie et qu'il n'y a pas de données de demande à envoyer.

Modifier pour Aaron (j'avais tort):

HttpWebRequest httpWebRequest = HttpWebRequest.Create("http://test") as HttpWebRequest; 
httpWebRequest.SendChunked = true; 
MessageBox.Show("|" + httpWebRequest.TransferEncoding + "|"); 

De System.Net.HttpWebRequest.SerializeHeaders():

if (this.HttpWriteMode == HttpWriteMode.Chunked) 
{ 
    this._HttpRequestHeaders.AddInternal("Transfer-Encoding", "chunked"); 
} 
else if (this.ContentLength >= 0L) 
{ 
    this._HttpRequestHeaders.ChangeInternal("Content-Length", this._ContentLength.ToString(NumberFormatInfo.InvariantInfo)); 
} 
+0

Cela violerait la spécification HTTP 1.1. Ce n'est pas clairement documenté, mais vous n'avez certainement pas besoin de définir la propriété 'ContentLength' lorsque vous utilisez' SendChunked = true'. Un paramètre remplace l'autre. – Aaronaught

+0

http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 "Si un message est reçu avec à la fois un champ d'en-tête Transfer-Encoding et un champ d'en-tête Content-Length, ce dernier DOIT Etre ignoré." Cela est donc autorisé selon la RFC, mais cela ne signifie pas qu'il est pris en charge par l'application qui reçoit le POST. La façon la plus facile est d'obtenir la longueur et de la régler, mais quel plaisir serait-il :) C'est toujours amusant d'explorer des solutions optimisées. –

+0

Eh bien, l'application recevant le POST est Apache, comme indiqué dans la question d'origine. À moins qu'il ne s'agisse d'une version très, très ancienne d'Apache, il supportera l'encodage en morceaux. – Aaronaught

Questions connexes