简体   繁体   English

在WebApi控制器中读取HttpContent

[英]Read HttpContent in WebApi controller

How can I read the contents on the PUT request in MVC webApi controller action. 如何在MVC webApi控制器操作中读取PUT请求中的内容。

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

I get empty string here :( 我在这里得到空字符串:(

What I need to do is: figure out "what properties" were modified/sent in the initial request (meaning that if the Contact object has 10 properties, and I want to update only 2 of them, I send and object with only two properties, something like this: 我需要做的是:弄清楚在初始请求中修改/发送了什么属性(意味着如果Contact对象有10个属性,并且我只想更新其中2个属性,我只发送和对象只有两个属性,像这样:

{

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

The expected end result is 预期的最终结果是

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

By design the body content in ASP.NET Web API is treated as forward-only stream that can be read only once. 根据设计,ASP.NET Web API中的主体内容被视为只能读取一次的仅向前流。

The first read in your case is being done when Web API is binding your model, after that the Request.Content will not return anything. 您的案例中的第一个读取是在Web API绑定模型时完成的,之后Request.Content将不返回任何内容。

You can remove the contact from your action parameters, get the content and deserialize it manually into object (for example with Json.NET): 您可以从操作参数中删除contact ,获取内容并将其手动反序列化为对象(例如使用Json.NET):

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

That should do the trick (assuming that accountId is URL parameter so it will not be treated as content read). 这应该做的伎俩(假设accountId是URL参数,因此它不会被视为内容读取)。

You can keep your CONTACT parameter with the following approach: 您可以使用以下方法保留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());
}

Returned for me the json representation of my parameter object, so I could use it for exception handling and logging. 为我返回参数对象的json表示,因此我可以将它用于异常处理和日志记录。

Found as accepted answer here 在这里找到接受的答案

Even though this solution might seem obvious, I just wanted to post it here so the next guy will google it faster. 虽然这个解决方案看起来很明显,但我只是想在这里发布,所以下一个人会更快地谷歌。

If you still want to have the model as a parameter in the method, you can create a DelegatingHandler to buffer the content. 如果您仍希望将模型作为方法中的参数,则可以创建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;
    }
}

And add it to the global message handlers: 并将其添加到全局消息处理程序:

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

This solution is based on the answer by Darrel Miller . 该解决方案基于Darrel Miller回答

This way all the requests will be buffered. 这样,所有请求都将被缓冲。

The easiest way to read the content of any request usually is to use an http proxy like fiddler 读取任何请求内容的最简单方法通常是使用像fiddler这样的http代理

That has the massive advantage of showing you all local traffic (plus the complete requests - headers etc) and lots of other requests which reading the Request content inside a particular action in a particular controller will not show you - eg 401 / 404 etc. 这具有显示所有本地流量(加上完整的请求 - 标头等)以及许多其他请求的巨大优势,这些请求读取特定控制器中特定操作内的请求内容将不会显示您 - 例如401/404等。

You can also use fiddler's composer to create test requests from scratch or by modifying previous requests. 您还可以使用fiddler的编写器从头开始创建测试请求或修改以前的请求。

If you for some reason cannot use a proxy or must view the request from inside the web app then this answer looks sensible 如果您由于某种原因无法使用代理或必须从Web应用程序内部查看请求,那么此答案看起来很合理

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM