在WebApi控制器中读取HttpContent


74

如何在MVC webApi控制器操作中读取PUT请求上的内容。

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

我在这里得到空字符串:(

我需要做的是:找出在初始请求中修改/发送的“哪些属性”(这意味着如果该Contact对象具有10个属性,而我只想更新其中2个属性,则发送和对象只有两个属性,像这样的东西:

{

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

预期的最终结果是

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

Answers:


138

通过设计,ASP.NET Web API中的主体内容被视为只能转发一次的只读流。

在您的情况下,当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参数,因此不会将其视为读取的内容)。


谢谢 是的,帐户ID是url参数。
马蒂(Marty)2012年

1
我想知道您是否可以在调用Model活页夹之前在请求内容上创建一个调用LoadIntoBuffer()的MessageHandler。–
Darrel Miller

@DarrelMiller我不确定ASP.NET Web API是否仍将绑定模型-需要进行测试。
tpeczek 2012年

这会导致死锁吗?
Airn5475 '18 -10-16

3
@ Airn5475可能是这样。您应该将动作签名切换为异步并使用await。
tpeczek

19

您可以使用以下方法保留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表示形式,因此我可以将其用于异常处理和记录。

在这里找到被接受的答案


4

即使此解决方案似乎很明显,我也只想将其发布在这里,以便下一个家伙更快地用Google搜索它。

如果您仍然希望将模型作为方法中的参数,则可以创建一个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());

该解决方案是基于答案达雷尔-米勒

这样,所有请求都将被缓冲。


我认为这可能会浪费我的服务器性能...但是它可以派上用场。
猎人Orionnoir
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.