0

I need access to RequestBody inside OnActionExecuting or OnActionExecuted filter, but I can not found concrete example how to use PipeReader to read full request body stream and return stream position to zero (in order to read request parameters by ControllerBase - if I read body OnActionExecuting or firstly return position to zero if I read in OnActionExecuting).

In my attribute Body always empty. Streamreader Error

However, API parameters is present.

Body present

Or maybe there is another way to receive Request Body in Action Filter for ControllerBase?

  • When you use `await new StreamReader(context.HttpContext.Request.Body).ReadToEndAsync();`, You can't get the value? – Xinran Shen Nov 21 '22 at 09:16
  • Of course, this stream is empty in OnActionExecuted, at least need to shift position to zero before try to read request stream. –  Nov 21 '22 at 18:18

1 Answers1

0

From your description, I think you wanna get request body in multiple times in asp.net core. But in asp.net core, the request can not be read once it is consumed. If you want to read the request body multiple times, you need to set:

context.Request.EnableBuffering()

Then to read the body stream you could for example do this:

string bodyContent = new StreamReader(Request.Body).ReadToEnd();

On the safer side, set the Request.Body.Position reset to 0. That way any code later in the request lifecycle will find the request body in the state just like it hasn’t been read yet.

Request.Body.Position = 0;

So you can set this code in either OnActionExecuting or OnActionExecuted method.

public void OnActionExecuting(ActionExecutingContext context)
        {
            
            context.HttpContext.Request.EnableBuffering();
            string bodyContent = new StreamReader(context.HttpContext.Request.Body).ReadToEnd();
            context.HttpContext.Request.Body.Position = 0;
        }

But please note that, Model binding happens before action filter, So Model binding will consume request body first and you can not read it in your action filter, You need to custom model binding and Apply the above configuration to it.

Xinran Shen
  • 8,416
  • 2
  • 3
  • 12
  • I'm sorry. This solution is not working. Directly I see error - "Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.". After reading with ReadToEndAsync.Result I see EMPTY result. StreamReader, of course, not related to Pipelines.StreamPipeReader and can not read request body. This is NET Core 6. –  Nov 25 '22 at 07:32
  • Check this [issue](https://stackoverflow.com/questions/47735133/asp-net-core-synchronous-operations-are-disallowed-call-writeasync-or-set-all) to solve the error. Have you custom your model binding to configure above settings? – Xinran Shen Nov 25 '22 at 07:37
  • I'm sorry. I check again with options.AllowSynchronousIO = True, but no. Request body can not read inside OnActionExecuting by this way. Model data present in controller, but bodyContent in OnActionExecuting is absent. –  Nov 25 '22 at 22:01
  • It's very strange, In my demo, I custom model binder and Apply the above configuration to it., I can read request body either in `OnActionExecuting` or `OnActionExecuted` method. – Xinran Shen Nov 28 '22 at 01:16
  • I can update question with screenshot from debugging (little bit later, I'm very sorry, now I must making another project). Maybe you will see what I going wrong. –  Nov 28 '22 at 16:20
  • Screenshots added. –  Nov 29 '22 at 19:09