HttpWebRequest chunked / async POST

嗨,我想将一些动态生成的内容上传到我的网络API。 在客户端我使用HttpWebRequest。 数据应该上传同步,我想写入流AFTER(!)我执行了HTTP请求。

(从服务器到客户端它确实工作正常,但从客户端到服务器我得到一些例外)。

客户端实现如下:

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 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... 

我在stream.write()上得到exception(NotSupportedException:流不支持并发IO读取或写入操作。)。

为什么我会在这里遇到例外情况。 有时第一次写入worke而后期写入抛出exception。 在开始时,stream.CanWrite属性为true,但在第一次或第二次或第四次写入后,它变为false …然后在下一次写入时抛出exception。

编辑:更改AllowWriteStreamBuffering没有帮助

附录: 我发现了我的问题。 此问题是由我的代码的顺序引起的。 我必须按此顺序调用它:

  • GetRequestStream(将异步写入流)(请求在第一次写入后发送到服务器)然后:
  • GetResponseAsync()
  • 的GetResponseStream()

我认为“GetResponseAsync”会触发客户端发送请求(现在只有标头)。 但是没有必要,因为在我将第一个比特写入流后,请求已经发送。

我问题的第二个原因:提琴手。 (Fiddler目前仅支持响应流而不是请求)

我发现了我的问题。

我的代码顺序导致了问题。

解决方案是按此顺序调用它:

  • GetRequestStream(将异步写入流)(请求在第一次写入后发送到服务器)然后:
  • GetResponseAsync()
  • 的GetResponseStream()

我的理解是“GetResponseAsync”触发客户端发送请求(现在只是头文件),但我发现它是一个不成功的步骤,因为请求已经在前几位写入后发送了流。

我的问题的第二个原因是Fiddler,但Fiddler只支持响应流,而不支持请求。

该代码实现了引用,’HttpWebRequest’类:

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

代码实现了引用,’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 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(); 

您正在同时在多个线程上使用HttpWebRequest对象。 response是与您的写入同时运行的任务。 这显然是线程不安全的。

而且,我看不到你想要达到的目标。 HTTP具有请求 – 响应模型。 在接收整个请求之前,服务器不能(通常)发送单个响应字节。 从理论上讲,这是可能的。 但这很不寻常,可能不受.NET BCL的支持。 这只能由您的(非常不寻常的)自定义HTTP服务器支持。