by WebSurfer
2021年4月15日 16:44
ASP.NET Core MVC / Razor Page には HttpRequest.Body プロパティというものがあって、要求のボディ部分を Stream として取得できます。しかしながら、それから StreamReader を使って内容を読みだすと空文字しか返ってきません。
それは何故なのかと、どのようにすれば読み出せるのかを書きます。それが何か役に立つのかと聞かれると自分は答えに窮しますが、とりあえず備忘録として。
読み出せないのは、上の画像の赤枠部分が示すように、Body プロパティから Stream を取得した時点で CanSeek が false になっており、Length プロパティも Position プロパティもサポートされていないからです。stackoverflow の記事 How to read ASP.NET Core Response.Body? によると "the Request.Body is a forward only stream that doesn't support seeking or reading the stream a second time" ということだそうです。
何故そういうことになっているかというと "to make the default configuration of request handling as lightweight and performant as possible" だからだそうです。それならそうと公式ドキュメントに書いておいてほしいと思うのですが・・・
どのようにすれば読み出せるかですが、HttpRequestRewindExtensions.EnableBuffering メソッドを設定することにより可能になります。
具体的には、startup.cs の Configure メソッドにミドルウェアとして以下のように登録します(Controller では効果は無いようです)。EnableBuffering メソッドにはオーバーロードが複数ありますので適当なものを選んでください。
app.Use(async (context, next) => {
context.Request.EnableBuffering();
await next();
});
上記の設定により、以下の画像の通り Body プロパティから取得した Stream の CanSeek が true になり、Position プロパティも有効になって巻き戻して(Position プロパティに 0 を設定して)複数回読むことが可能になります。
ただ、そのような設定をして複数回読めるようにすると、性能上の劣化が生じる可能性はあるかもしれません。
あと、stackoverflow の記事に書いてあるように、StreamReader を初期化する際は using は使わない、読み終わったら Position プロパティを 0 に設定しておくという点も注意した方が良さそうです。