54

我在 ApiController 类中有以下 Web API 方法:

public HttpResponseMessage Post([FromBody]byte[] incomingData)
{
  ...
}

我想incomingData成为 POST 的原始内容。但似乎 Web API 堆栈尝试使用 JSON 格式化程序解析传入数据,这会导致客户端的以下代码失败:

new WebClient().UploadData("http://localhost:15134/api/Foo", new byte[] { 1, 2, 3 });

有一个简单的解决方法吗?

4

7 回答 7

58

对于遇到此问题的其他任何人,解决方案是定义不带参数的 POST 方法,并通过以下方式访问原始数据Request.Content

public HttpResponseMessage Post()
{
  Request.Content.ReadAsByteArrayAsync()...
  ...
于 2012-11-06T09:51:08.817 回答
37

If you need the raw input in addition to the model parameter for easier access, you can use the following:

using (var contentStream = await this.Request.Content.ReadAsStreamAsync())
{
    contentStream.Seek(0, SeekOrigin.Begin);
    using (var sr = new StreamReader(contentStream))
    {
        string rawContent = sr.ReadToEnd();
        // use raw content here
    }
}

The secret is using stream.Seek(0, SeekOrigin.Begin) to reset the stream before trying to read the data.

于 2016-07-11T10:18:06.367 回答
18

其他答案建议删除输入参数,但这会破坏您现有的所有代码。为了正确回答这个问题,一个更简单的解决方案是创建一个如下所示的函数(感谢下面的 Christoph 提供此代码):

private async Task<String> getRawPostData()
{
    using (var contentStream = await this.Request.Content.ReadAsStreamAsync())
    {
        contentStream.Seek(0, SeekOrigin.Begin);
        using (var sr = new StreamReader(contentStream))
        {
            return sr.ReadToEnd();
        }
    }
}

然后在你的 web api 调用中获取原始发布的数据,如下所示:

public HttpResponseMessage Post ([FromBody]byte[] incomingData)
{
    string rawData = getRawPostData().Result;

    // log it or whatever

    return Request.CreateResponse(HttpStatusCode.OK);
}
于 2016-07-20T03:39:35.953 回答
13

在 MVC 6 中,请求似乎没有“内容”属性。这就是我最终做的事情:

[HttpPost]
public async Task<string> Post()
{
    string content = await new StreamReader(Request.Body).ReadToEndAsync();
    return "SUCCESS";
}
于 2016-03-17T02:23:21.520 回答
11

我接受了 LachlanB 的回答,并将它放在一个实用程序类中,其中包含一个可以在所有控制器中使用的静态方法。

public class RawContentReader
{
    public static async Task<string> Read(HttpRequestMessage req)
    {
        using (var contentStream = await req.Content.ReadAsStreamAsync())
        {
            contentStream.Seek(0, SeekOrigin.Begin);
            using (var sr = new StreamReader(contentStream))
            {
                return sr.ReadToEnd();
            }
        }
    }
}

然后我可以通过这种方式从我的任何 ApiController 方法中调用它:

string raw = await RawContentReader.Read(this.Request);
于 2016-11-15T21:22:28.063 回答
1

或者干脆

string rawContent = await Request.Content.ReadAsStringAsync();

确保在处理原始请求之前在 THE SAME THREAD 上运行上述行

注意:这是针对 ASP.NET MVC 5

于 2021-02-22T09:02:59.610 回答
0

在代码块下面的控制器中获取请求正文原始有效负载

 string requestBody = string.Empty;
        using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
        {
            requestBody = await reader.ReadToEndAsync();
        }
于 2021-10-15T19:09:58.953 回答