.NET: Sie müssen ContentLength-Byte für den Anforderungsstream schreiben, bevor Sie [Begin]GetResponse aufrufen

.NET: Sie müssen ContentLength-Byte für den Anforderungsstream schreiben, bevor Sie [Begin]GetResponse aufrufen

Ein formell richtiger Http-Request, der beispielsweise über die HttpWebRequest-Klasse von .NET erzeugt wird, wirft die Exception

.NET: Sie müssen ContentLength-Byte für den Anforderungsstream schreiben, bevor Sie [Begin]GetResponse aufrufen

Schaut man sich den Code an,  wird die Content-Length Eigenschaft und somit auch der dazugehörige Header korrekt gesetzt – Dementsprechend erscheint die Fehlermeldung recht verwirrend. Beim genaueren Betrachten wird jedoch ein Denkfehler des Entwicklers sichtbar. Zur Verdeutlichung des Problemes ein simples Beispiel:

        public void SendRequest(string requestUrl, string body) {
            var request = (HttpWebRequest)WebRequest.Create(requestUrl);
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = body.Length;
            var bodyAsBytes = Encoding.UTF8.GetBytes(body);
            request.GetRequestStream().Write(bodyAsBytes, 0, bodyAsBytes.Length);
        }

Die Variable body wird ein String wie beispielsweise username=Peter&password=123 sein. Natürlich ließe sich dieses umständliche zusammenbasteln deutlich vereinfachen, in dem etwa ein Dictionary übergeben und später entsprechend aufbereitet wird. Um den Fokus auf das wesentliche zu setzen, habe ich diese Helfer an dieser Stelle bewusst entfernt. Das Problem ist nämlich, dass die Länge des Strings gesetzt wird. In den Anforderungsstream wird der Body jedoch als UTF8-Kodiertes Byte-Array geschrieben. Die Länge dieser beiden Varianten kann sich unterscheiden, obwohl die gleichen Daten enthalten sind. In diesem Fall erwartet der Server anhand des ContentLength-Headers mehr oder weniger Daten, als er tatsächlich erhält.

Korrekterweise müssten wir daher die Länge des Byte-Arrays bodyAsBytes verwenden:

var bodyAsBytes = Encoding.UTF8.GetBytes(body);
request.ContentLength = bodyAsBytes.Length;

Dies ist allerdings an dieser Stelle gar nicht notwendig: Das .NET Framework ist intelligent genug, die Länge des RequestStreams automatisch vor dem Absenden als Content-Length Header zu setzen. Somit kann dieser Aufruf komplett wegfallen, und die obige Beispielmethode lässt sich folgendermaßen reduzieren:

        public void SendRequest(string requestUrl, string body) {
            var request = (HttpWebRequest)WebRequest.Create(requestUrl);
            request.ContentType = "application/x-www-form-urlencoded";
            var bodyAsBytes = Encoding.UTF8.GetBytes(body);
            request.GetRequestStream().Write(bodyAsBytes, 0, bodyAsBytes.Length);
        }

Die Fehlerquelle welche zur ursprünglichen Exception geführt hat, haben wir damit ebenfalls umgangen.

Leave a Reply