Getting raw POST data from Web API method

C#asp.net Web-Api

C# Problem Overview


I have the following Web API method in an ApiController class:

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

I want incomingData to be the raw content of the POST. But it seems that the Web API stack attempts to parse the incoming data with the JSON formatter, and this causes the following code on the client side to fail:

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

Is there a simple workaround for this?

C# Solutions


Solution 1 - C#

For anyone else running into this problem, the solution is to define the POST method with no parameters, and access the raw data via Request.Content:

public HttpResponseMessage Post()
{
  Request.Content.ReadAsByteArrayAsync()...
  ...

Solution 2 - C#

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.

Solution 3 - C#

The other answers suggest removing the input parameter, but that will break all of your existing code. To answer the question properly, an easier solution is to create a function that looks like this (Thanks to Christoph below for this code):

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();
        }
    }
}

and then get the raw posted data inside your web api call like so:

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

    // log it or whatever

    return Request.CreateResponse(HttpStatusCode.OK);
}

Solution 4 - C#

In MVC 6 Request doesn't seem to have a 'Content' property. Here's what I ended up doing:

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

Solution 5 - C#

I took LachlanB's answer and put it in a utility class with a single static method that I can use in all my controllers.

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();
            }
        }
    }
}

Then I can call it from any of my ApiController's methods this way:

string raw = await RawContentReader.Read(this.Request);

Solution 6 - C#

Or simply

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

make sure you run the above line on THE SAME THREAD before the original request is DISPOSED

Note: This is for ASP.NET MVC 5

Solution 7 - C#

in the controller below codeBlock gets the request body raw payload

 string requestBody = string.Empty;
        using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
        {
            requestBody = await reader.ReadToEndAsync();
        }

Solution 8 - C#

In .NET 6 i've done something like this:

JsonObject? requestBodyJSON = await context.Request.ReadFromJsonAsync<JsonObject>();
string rawRequestBody = requestBodyJSON.ToJsonString();

So basically read body as JSON and deserialize it in JsonObject, and after that just call .ToJsonString() and you get raw body data. Good thing is that from this JsonObject you can parse it to all basic types like Dictionary, List, Array, etc...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoe AlbahariView Question on Stackoverflow
Solution 1 - C#Joe AlbahariView Answer on Stackoverflow
Solution 2 - C#Christoph HeroldView Answer on Stackoverflow
Solution 3 - C#RocklanView Answer on Stackoverflow
Solution 4 - C#Jason GoemaatView Answer on Stackoverflow
Solution 5 - C#William T. MallardView Answer on Stackoverflow
Solution 6 - C#Adel MouradView Answer on Stackoverflow
Solution 7 - C#rajquestView Answer on Stackoverflow
Solution 8 - C#HazaaaView Answer on Stackoverflow