Getting raw POST data from Web API method
C#asp.net Web-ApiC# 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...