Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read raw Request.Body in Asp.Net Core MVC Action with Route Parameters

I need to process the raw request body in and MVC core controller that has route parameters

[HttpPut]
[Route("api/foo/{fooId}")]
public async Task Put(string fooId)
{
   reader.Read(Request.Body).ToList();
   await _store.Add("tm", "test", data);
}

but It seems like the model binder has already consumed the request stream by the time it gets to the controller.

If I remove the route parameters, I can then access the request stream (since the framework will no longer process the stream to look for parameters). How can I specify both route parameters and be able to access Request Body without having to manually parse request URI etc.?

I have tried decorating my parameters with [FromRoute] but it had no effect.

  • Please note I cannot bind the request body to an object and have framework handle the binding, as I am expecting an extremely large payload that needs to be processed in chunks in a custom manner.
  • There are no other controller, no custom middle-ware, filters, serialzier, etc.
  • I do not need to process the body several times, only once
  • storing the stream in a temp memory or file stream is not an options, I simply want to process the request body directly.

How can I get the framework to bind paramters from Uri, QueryString, etc. but leave the request body to me?

like image 378
hnafar Avatar asked Nov 02 '25 08:11

hnafar


1 Answers

Define this attribute in your code:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
   public void OnResourceExecuting(ResourceExecutingContext context)
   {
       var factories = context.ValueProviderFactories;
       factories.RemoveType<FormValueProviderFactory>();
       factories.RemoveType<JQueryFormValueProviderFactory>();
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}    

If you're targeting .Net Core 3 you also need to add

factories.RemoveType<FormFileValueProviderFactory>();

Now decorate your action method with it:

[HttpPut]
[Route("api/foo/{fooId}")]
[DisableFormValueModelBinding]
public async Task Put(string fooId)
{
  reader.Read(Request.Body).ToList();
  await _store.Add("tm", "test", data);
}

The attribute works by removing Value Providers which will attempt to read the request body, leaving just those which supply values from the route or the query string.

HT @Tseng for the link Uploading large files with streaming which defines this attribute

like image 152
Samuel Jack Avatar answered Nov 05 '25 16:11

Samuel Jack