【问题标题】:Read HttpContent in WebApi controller在 WebApi 控制器中读取 HttpContent
【发布时间】:2012-09-11 17:22:30
【问题描述】:

如何在 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"}

【问题讨论】:

    标签: c# asp.net-mvc asp.net-web-api httpcontent


    【解决方案1】:

    尽管这个解决方案看起来很明显,但我只是想把它贴在这里,以便下一个人能更快地用谷歌搜索它。

    如果你还想让模型作为方法中的参数,你可以创建一个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

    这样所有的请求都会被缓冲。

    【讨论】:

    • 我认为这可能会降低我的服务器性能......但它可能会派上用场。
    【解决方案2】:

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

    发现为已接受的答案here

    【讨论】:

      【解决方案3】:

      通过设计,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 参数。
      • 我想知道您是否可以在模型绑定器启动之前在请求内容上创建一个调用 LoadIntoBuffer() 的 MessageHandler。
      • @DarrelMiller 我不确定 ASP.NET Web API 是否仍会绑定模​​型 - 需要测试。
      • 这会导致死锁吗?
      • @Airn5475 事实上,它可能。您应该将动作签名切换为异步并使用等待。
      猜你喜欢
      • 1970-01-01
      • 2014-11-12
      • 1970-01-01
      • 2017-03-22
      • 2020-10-12
      • 2015-03-14
      • 2014-10-08
      • 2020-09-07
      相关资源
      最近更新 更多