web-dev-qa-db-ja.com

Web ApiコントローラーでHttpContentを読み取る

MVC webApiコントローラーアクションでPUTリクエストのコンテンツを読み取るにはどうすればよいですか。

[HttpPut]
public HttpResponseMessage Put(int accountId, Contact contact)
{
    var httpContent = Request.Content;
    var asyncContent = httpContent.ReadAsStringAsync().Result;
...

ここで空の文字列を取得します:(

私がする必要があるのは、最初のリクエストで「どのプロパティ」が変更/送信されたかを把握することです(つまり、Contactオブジェクトに10個のプロパティがあり、そのうち2つだけを更新したい場合は、送信してオブジェクト次のような2つのプロパティのみがあります。

{

    "FirstName": null,
    "LastName": null,
    "id": 21
}

予想される最終結果は

List<string> modified_properties = {"FirstName", "LastName"}
65
Marty

設計により、ASP.NET Web APIの本文コンテンツは、1回だけ読み取り可能なフォワード専用ストリームとして扱われます。

あなたの場合の最初の読み取りは、Web APIがモデルをバインドしているときに行われます。その後、Request.Contentは何も返しません。

アクションパラメーターからcontactを削除し、コンテンツを取得し、手動でオブジェクトにデシリアライズできます(たとえば、Json.NETを使用)。

[HttpPut]
public HttpResponseMessage Put(int accountId)
{
    HttpContent requestContent = Request.Content;
    string jsonContent = requestContent.ReadAsStringAsync().Result;
    CONTACT contact = JsonConvert.DeserializeObject<CONTACT>(jsonContent);
    ...
}

これでうまくいくはずです(accountIdがURLパラメーターであり、コンテンツの読み取りとして扱われないと仮定します)。

124
tpeczek

CONTACTパラメーターは、次のアプローチで保持できます。

using (var stream = new MemoryStream())
{
    var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
    context.Request.InputStream.Seek(0, SeekOrigin.Begin);
    context.Request.InputStream.CopyTo(stream);
    string requestBody = Encoding.UTF8.GetString(stream.ToArray());
}

パラメータオブジェクトのJSON表現が返されたため、例外処理とログ記録に使用できました。

受け入れられた答えとして見つかった こちら

18
Anytoe

この解決策は明白に思えるかもしれませんが、次の人がより速くグーグルで検索できるように、ここに投稿したかっただけです。

メソッドのパラメーターとしてモデルを引き続き使用する場合は、DelegatingHandlerを作成してコンテンツをバッファーできます。

internal sealed class BufferizingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        await request.Content.LoadIntoBufferAsync();
        var result = await base.SendAsync(request, cancellationToken);
        return result;
    }
}

そして、グローバルメッセージハンドラーに追加します。

configuration.MessageHandlers.Add(new BufferizingHandler());

このソリューションは answer by Darrel Miller に基づいています。

これにより、すべてのリクエストがバッファリングされます。

4
derwasp