Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 668 Vote(s) - 3.46 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to read request body in an asp.net core webapi controller?

#1
I'm trying to read the request body in the `OnActionExecuting` method, but I always get `null` for the body.

var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();

I have tried to explicitly set the stream position to 0, but that also didn't work. Since this is ASP.NET Core, things are a little different I think. I can see all the samples here referring to old web API versions.

Is there any other way of doing this?
Reply

#2
To be able to rewind the request body, @Jean's answer helped me come up with a solution that seems to work well. I currently use this for Global Exception Handler Middleware but the principle is the same.

I created a middleware that basically enables the rewind on the request body (instead of a decorator).

using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableRequestRewindMiddleware
{
private readonly RequestDelegate _next;

public EnableRequestRewindMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task Invoke(HttpContext context)
{
context.Request.EnableRewind();
await _next(context);
}
}

public static class EnableRequestRewindExtension
{
public static IApplicationBuilder UseEnableRequestRewind(this IApplicationBuilder builder)
{
return builder.UseMiddleware<EnableRequestRewindMiddleware>();
}
}

This can then be used in your `Startup.cs` like so:

[...]
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
[...]
app.UseEnableRequestRewind();
[...]
}

Using this approach, I have been able to rewind the request body stream successfully.
Reply

#3
The `IHttpContextAccessor` method does work if you wish to go this route.

*TLDR;*

* Inject the `IHttpContextAccessor`

* Rewind -- `HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);`

* Read --
```System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body);
JObject asObj = JObject.Parse(sr.ReadToEnd());
```

*More* -- An attempt at a concise, non-compiling, example of the items you'll need to ensure are in place in order to get at a useable `IHttpContextAccessor`.
Answers have pointed out correctly that you'll need to seek back to the start when you try to read the request body. The `CanSeek`, `Position` properties on the request body stream helpful for verifying this.

[.NET Core DI Docs][1]


// First -- Make the accessor DI available
//
// Add an IHttpContextAccessor to your ConfigureServices method, found by default
// in your Startup.cs file:
// Extraneous junk removed for some brevity:
public void ConfigureServices(IServiceCollection services)
{
// Typical items found in ConfigureServices:
services.AddMvc(config => { config.Filters.Add(typeof(ExceptionFilterAttribute)); });
// ...

// Add or ensure that an IHttpContextAccessor is available within your Dependency Injection container
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

// Second -- Inject the accessor
//
// Elsewhere in the constructor of a class in which you want
// to access the incoming Http request, typically
// in a controller class of yours:
public class MyResourceController : Controller
{
public ILogger<PricesController> Logger { get; }
public IHttpContextAccessor HttpContextAccessor { get; }

public CommandController(
ILogger<CommandController> logger,
IHttpContextAccessor httpContextAccessor)
{
Logger = logger;
HttpContextAccessor = httpContextAccessor;
}

// ...

// Lastly -- a typical use
[Route("command/resource-a/{id}")]
[HttpPut]
public ObjectResult PutUpdate([FromRoute] string id, [FromBody] ModelObject requestModel)
{
if (HttpContextAccessor.HttpContext.Request.Body.CanSeek)
{
HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body);
JObject asObj = JObject.Parse(sr.ReadToEnd());

var keyVal = asObj.ContainsKey("key-a");
}
}
}

[1]:

[To see links please register here]

Reply

#4
for read of `Body` , you can to read asynchronously.

use the `async` method like follow:


public async Task<IActionResult> GetBody()
{
string body="";
using (StreamReader stream = new StreamReader(Request.Body))
{
body = await stream.ReadToEndAsync();
}
return Json(body);
}


**Test with postman:**

[![enter image description here][1]][1]

It's working well and tested in `Asp.net core` version `2.0 , 2.1 , 2.2, 3.0`.

I hope is useful.


[1]:
Reply

#5
I also wanted to read the Request.Body without automatically map it to some action parameter model. Tested a lot of different ways before solved this. And I didn´t find any working solution described here. This solution is currently based on the .NET Core 3.0 framework.

reader.readToEnd() seamed like a simple way, even though it compiled, it throwed an runtime exception required me to use async call. So instead I used ReadToEndAsync(), however it worked sometimes, and sometimes not. Giving me errors like, cannot read after stream is closed. The problem is that we cannot guarantee that it will return the result in the same thread (even if we use the await). So we need some kind of callback. This solution worked for me.

[Route("[controller]/[action]")]
public class MyController : ControllerBase
{

// ...

[HttpPost]
public async void TheAction()
{
try
{
HttpContext.Request.EnableBuffering();
Request.Body.Position = 0;
using (StreamReader stream = new StreamReader(HttpContext.Request.Body))
{
var task = stream
.ReadToEndAsync()
.ContinueWith(t => {
var res = t.Result;
// TODO: Handle the post result!
});

// await processing of the result
task.Wait();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to handle post!");
}
}
Reply

#6
I was able to read request body in an asp.net core 3.1 application like this (together with a simple middleware that enables buffering -enable rewinding seems to be working for earlier .Net Core versions-) :

var reader = await Request.BodyReader.ReadAsync();
Request.Body.Position = 0;
var buffer = reader.Buffer;
var body = Encoding.UTF8.GetString(buffer.FirstSpan);
Request.Body.Position = 0;

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through