从Web API方法获取原始POST数据

Joe*_*ari 44 c# asp.net-web-api

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

public HttpResponseMessage Post([FromBody]byte[] incomingData)
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Joe*_*ari 53

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

public HttpResponseMessage Post()
{
  Request.Content.ReadAsByteArrayAsync()...
  ...
Run Code Online (Sandbox Code Playgroud)

  • 我需要类似的东西,但对于字符串,并确保POST方法中没有参数最终是使用等效的`ReadAsStringAsync`必不可少的,否则它是空的. (4认同)
  • 谢谢你。在 MVC6 中,为了获取完整的正文,我必须删除参数并手动读取“Request.Body”。 (2认同)

Chr*_*old 26

如果除了model参数之外还需要原始输入以便于访问,可以使用以下命令:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

秘密stream.Seek(0, SeekOrigin.Begin)用于在尝试读取数据之前重置流.


Roc*_*lan 15

其他答案建议删除输入参数,但这将破坏所有现有代码.要正确回答这个问题,更简单的解决方案是创建一个看起来像这样的函数(感谢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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

    // log it or whatever

    return Request.CreateResponse(HttpStatusCode.OK);
}
Run Code Online (Sandbox Code Playgroud)


Wil*_*ard 7

我把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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

string raw = await RawContentReader.Read(this.Request);
Run Code Online (Sandbox Code Playgroud)


Jas*_*aat 6

在MVC 6中,请求似乎没有'Content'属性。我最终要做的是:

[HttpPost]
public async Task<string> Post()
{
    string content = await new StreamReader(Request.Body).ReadToEndAsync();
    return "SUCCESS";
}
Run Code Online (Sandbox Code Playgroud)