web-dev-qa-db-ja.com

Http Request Inputストリームを2回読み取れないのはなぜですか?

デバッグコードをいくつかテストして、デバッグコードが期待どおりに動作していませんでした。以下の例は、私の質問を説明するための単純化されたコードです。

これは.NET 4にあり、WebApiを使用して、デバッグコードでhttpリクエストの本文を出力しようとしています。これを行うには、入力ストリームをシークしてストリームを読み取ります。最初は問題なく動作しますが、もう一度読み込もうとすると、空の文字列が表示されます。

InputStreamを再度シークして読み取ることができないのはなぜですか?以下の例では、body2は常に空です。 2番目のセットでは、CanSeekはまだtrueであり、ReadToEnd()への2番目の呼び出しは、デフォルトを上書きする空の文字列を返します。

using System.IO;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;

public class TestController : ApiController
{

    public class TestOutuput
    {
        public string firstRead;
        public string secondRead;
    }

    public HttpResponseMessage Post()
    {
        string body1 = "default for one";
        string body2 = "default for two";
        if (HttpContext.Current.Request.InputStream.CanSeek)
        {
            HttpContext.Current.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
        }
        using (var reader = new StreamReader(HttpContext.Current.Request.InputStream))
        {
            body1 = reader.ReadToEnd();
        }

        if (HttpContext.Current.Request.InputStream.CanSeek)
        {
            HttpContext.Current.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
        }
        using (var reader2 = new StreamReader(HttpContext.Current.Request.InputStream))
        {
            // this is always empty, even after seek back to Origin
            body2 = reader2.ReadToEnd();
        }

        TestOutuput testOutput = new TestOutuput() { firstRead = body1, secondRead = body2 };
        HttpResponseMessage response = new HttpResponseMessage();
        return Request.CreateResponse<TestOutuput>(HttpStatusCode.OK, testOutput);
    }
}
19
Michael Levy

StreamReaderは、破棄されるときに、指定されたストリームでDisposeを呼び出します。ストリームを開いたままにするには、StreamReader適切なコンストラクタ を使用します。あるいは、バッファにコピーするだけです。 MSDNから:

ストリームから読み取る場合は、ストリームの内部バッファーと同じサイズのバッファーを使用する方が効率的です。

たとえば この質問 を参照してください。

22
Patko

HttpContext.Current.Request.InputStream.Position=0;

位置を読み取ると、最後の値に移動し、そこから2回目の読み取りを試みます。読む前に、位置をゼロに設定してください。

それが役に立てば幸い。

5
ANG