C# 在 WebApi 控制器中读取 HttpContent

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12494067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 23:27:01  来源:igfitidea点击:

Read HttpContent in WebApi controller

c#asp.net-mvcasp.net-web-apihttpcontent

提问by Marty

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 Contactobject 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 tpeczek

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.Contentwill not return anything.

您的案例中的第一次读取是在 Web API 绑定您的模型时完成的,之后Request.Content将不会返回任何内容。

You can remove the contactfrom 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 accountIdis URL parameter so it will not be treated as content read).

这应该可以解决问题(假设它accountId是 URL 参数,因此它不会被视为内容读取)。

回答by Anytoe

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

在此处找到可接受的答案

回答by derwasp

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 DelegatingHandlerto 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 answerby Darrel Miller.

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

This way all the requests will be buffered.

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