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"}
設計により、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パラメーターであり、コンテンツの読み取りとして扱われないと仮定します)。
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表現が返されたため、例外処理とログ記録に使用できました。
受け入れられた答えとして見つかった こちら
この解決策は明白に思えるかもしれませんが、次の人がより速くグーグルで検索できるように、ここに投稿したかっただけです。
メソッドのパラメーターとしてモデルを引き続き使用する場合は、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 に基づいています。
これにより、すべてのリクエストがバッファリングされます。