6

こんにちは、動的に生成されたコンテンツを Web API にアップロードしたいと考えています。クライアントでは、HttpWebRequest を使用します。データは同期してアップロードする必要があり、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<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...

stream.write() で例外が発生します (NotSupportedException: The stream does not support parallel IO read or write operations.)。

ここで例外が発生するのはなぜですか。場合によっては、最初の書き込みが機能し、後の書き込みで例外がスローされることがあります。最初は stream.CanWrite プロパティは true ですが、1 回目または 2 回目または 3 回目の書き込みの後は false になります...そして、次の書き込みで例外がスローされます。

編集:AllowWriteStreamBufferingを変更しても役に立たなかった

付録: 問題が見つかりました。この問題は、私のコードの順序が原因です。次の順序で呼び出す必要があります。

  • GetRequestStream (ストリームへの非同期書き込み) (リクエストは最初の書き込みの後にサーバーに送信されます) の場合:
  • GetResponseAsync()
  • GetResponseStream()

「GetResponseAsync」がクライアントをトリガーしてリクエストを送信すると思いました(今のところヘッダーのみ)。ただし、最初のビットをストリームに書き込んだ後、要求は既に送信されているため、必要ありません。

私の問題の 2 番目の原因: Fiddler。(Fiddler は現在、要求ではなく、応答のストリーミングのみをサポートしています)

4

2 に答える 2

9

問題が見つかりました。

コードの順序が問題の原因でした。

解決策は、次の順序で呼び出すことです。

  • GetRequestStream (ストリームへの非同期書き込み) (リクエストは最初の書き込みの後にサーバーに送信されます) の場合:
  • GetResponseAsync()
  • GetResponseStream()

私の理解では、「GetResponseAsync」がクライアントにリクエストを送信するようにトリガーします(今のところヘッダーのみ)が、最初の数ビットがストリーム。

私の問題の 2 番目の原因は 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<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);

}

コードは、「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();
于 2014-08-29T12:15:02.510 に答える