ASP.NET MVCでPOSTされたデータを取得する

ASP.NET MVCでPOSTされたデータを取得したときのこと。

たとえば、

[HttpPost]
public ActionResult CreateData(string value)
{
    (省略)
}

のようなアクションメソッドがあったとしてPOSTされたデータを文字列として出力したい場合(ログ出力など)には、アクションメソッドのパラメータvalueを取得して間単に出力できます。

そして、それなりの規模になるとアクションメソッドの数もかなり多くなってくるため、その文字列出力処理も当然共通化しておきたいと考えるようになります。

ところが、アクションメソッドのパラメータをもとに出力するという共通処理は現実的ではありません。stringやintといった型だけでなく、独自に作成した型も対象としたい場合もあり、その型も様々なプロパティーを持ってたり、それがCollectionだったり、と多岐に渡ります。そうなってくると、GetType().GetProperties()で単純に取得することもできず、難しくなってきます。

根本的に見直さなければなりません。そこで、アクションメソッドのパラメータを使用しない方法を考えます。

アクションメソッド(POST)のパラメータはHTTPリクエストボディをパースしてControllerに渡されているのですが、パース前のHTTPリクエストから直接文字列として取得してしまえばいい、ということに気づきました。シリアライズしないので、こちらのほうがよっぽど単純ですね。

ということで、HttpRequestBaseのオブジェクトであるRequestを使います。

[HttpPost]
public ActionResult CreateData(userClass object)
{
    using (StreamReader reader = new StreamReader(Request.InputStream, Encoding.UTF8))
    {
        string output = reader.ReadToEnd();
    }

    (省略)
}

よし取れた、と思ったのですが、取れたのは空文字でした。
ググっても上と同じようなソースコードが見つかります。
が、その中に以下のようなソースコードもありました。

[HttpPost]
public ActionResult CreateData(userClass object)
{
    Request.InputStream.Position = 0;
    using (StreamReader reader = new StreamReader(Request.InputStream, Encoding.UTF8))
    {
        string output = reader.ReadToEnd();
    }

    (省略)
}

以下の記事によるとMVC2からMVC4の間で動作が変わったとのこと。


asp.net mvc - MVC 4 advancing Request.InputStream before reaching ModelBinder - Stack Overflow

これで目的の文字列を取得して出力することができました。