HttpWebRequest chunked / async POST

Hi, I want to upload some dynamic generated content to my web api. On the client, I am using HttpWebRequest. The data must be loaded synchronization, and I want to write to the stream AFTER (!) I made an HTTP request.

(It works fine from server to client, but I get some exceptions from client to server).

The client implementation looks like this:

HttpWebRequest httpWebRequest = HttpWebRequest.Create(myUrl) as HttpWebRequest; httpWebRequest.Method = "POST"; httpWebRequest.Headers["Authorization"] = "Basic " + ... ; httpWebRequest.PreAuthenticate = true; httpWebRequest.SendChunked = true; //httpWebRequest.AllowWriteStreamBuffering = false; //does not help... httpWebRequest.ContentType = "application/octet-stream"; Stream st = httpWebRequest.GetRequestStream(); Task<WebResponse> response = httpWebRequest.GetResponseAsync(); // NOW: Write after GetResponse() var b = Encoding.UTF8.GetBytes("Test1"); st.Write(b, 0, b.Length); b = Encoding.UTF8.GetBytes("Test2"); st.Write(b, 0, b.Length); b = Encoding.UTF8.GetBytes("Test3"); st.Write(b, 0, b.Length); st.Close(); var x = response.Result; Stream resultStream = x.GetResponseStream(); //do some output... 

I get exceptions (NotSupportedException: the stream does not support simultaneous read or write IO.) Operations in stream.write ().

Why am I getting exceptions. The first one writes worke several times, and the late entry throws an exception. At first, the stream.CanWrite property is true, but after the first, second, or third writing, it becomes false ... And then an exception is thrown to the next record.

Edit: changing the AllowWriteStreamBuffering parameter did not help

Application: I found my problem. This problem is caused by the order of my code. I have to call it in the following order:

  • GetRequestStream (writing async to the stream) (the request is sent to the server after the first recording) then:
  • GetResponseAsync ()
  • GetResponseStream ()

I thought that "GetResponseAsync" starts the client to send a request (now only headers). But this is not necessary, because the request is already sent after I write the first bits to the stream.

The second reason for my problems: Violinist. (Fiddler currently only supports response streams, not requests)

+4
c # asynchronous stream chunked
source share
2 answers

I found my problem.

The order of my code caused the problem.

The solution is to call it in the following order:

  • GetRequestStream (writing async to the stream) (the request is sent to the server after the first recording), and then:
  • GetResponseAsync ()
  • GetResponseStream ()

I understand that "GetResponseAsync" starts the client to send the request (currently only headers), but I found that it was an unreasonable step because the request was already sent after the first few bits were written to the stream.

The second reason for my problems is Fiddler, but Fiddler only supports response streams, not requests.

The code obtained by reference is the HttpWebRequest class:

 HttpWebRequest httpWebRequest = HttpWebRequest.Create("http://xxx") as HttpWebRequest; httpWebRequest.Method = "POST"; httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("user:pw")); httpWebRequest.PreAuthenticate = true; httpWebRequest.SendChunked = true; httpWebRequest.AllowWriteStreamBuffering = false; httpWebRequest.AllowReadStreamBuffering = false; httpWebRequest.ContentType = "application/octet-stream"; Stream st = httpWebRequest.GetRequestStream(); Console.WriteLine("Go"); try { st.Write(buffer, 0, buffer.Length); //with the first write, the request will be send. st.Write(buffer, 0, buffer.Length); st.Write(buffer, 0, buffer.Length); for (int i = 1; i <= 10; i++) { st.Write(buffer, 0, buffer.Length); //still writing while I can read on the stream at my ASP.NET web api } } catch (WebException ex) { var y = ex.Response; } finally { st.Close(); } // Now we can read the response from the server in chunks Task<WebResponse> response = httpWebRequest.GetResponseAsync(); Stream resultStream = response.Result.GetResponseStream(); byte[] data = new byte[1028]; int bytesRead; while ((bytesRead = resultStream.Read(data, 0, data.Length)) > 0) { string output = System.Text.Encoding.UTF8.GetString(data, 0, bytesRead); Console.WriteLine(output); } 

Code obtained by reference, class "HttpClient":

 HttpClientHandler ch = new HttpClientHandler(); HttpClient c = new HttpClient(ch); c.DefaultRequestHeaders.TransferEncodingChunked = true; c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes("user:pw"))); Stream stream = new MemoryStream(); AsyncStream asyncStream = new AsyncStream(); // Custom implementation of the PushStreamContent with the method, "WriteToStream()". PushStreamContent streamContent = new PushStreamContent(asyncStream.WriteToStream); HttpRequestMessage requestMessage = new HttpRequestMessage(new HttpMethod("POST"), "http://XXX") { Content = streamContent }; requestMessage.Headers.TransferEncodingChunked = true; HttpResponseMessage response = await c.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead); // The request has been sent, since the first write in the "WriteToStream()" method. response.EnsureSuccessStatusCode(); Task<Stream> result = response.Content.ReadAsStreamAsync(); byte[] data = new byte[1028]; int bytesRead; while ((bytesRead = await result.Result.ReadAsync(data, 0, data.Length)) > 0) { string output = System.Text.Encoding.UTF8.GetString(data, 0, bytesRead); Console.WriteLine(output); } Console.ReadKey(); 
+6
source

You are using HttpWebRequest objects for multiple threads simultaneously. response is a task that runs at the same time as your records. This is clearly unsafe.

In addition, I do not see what you want to achieve. HTTP has a request-response model. The server cannot (usually) send one byte of response before receiving the entire request. It is theoretically possible. But this is very unusual and probably not supported by .NET BCL. This will only be supported by the (very unusual) custom HTTP server.

0
source

All Articles