Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read request body twice

I am trying to read the body in a middleware for authentication purposes, but when the request gets to the api controller the object is empty as the body has already been read. Is there anyway around this. I am reading the body like this in my middleware.

var buffer = new byte[ Convert.ToInt32( context.Request.ContentLength ) ]; await context.Request.Body.ReadAsync( buffer, 0, buffer.Length ); var body = Encoding.UTF8.GetString( buffer ); 
like image 629
Jake Rote Avatar asked Jul 13 '15 17:07

Jake Rote


1 Answers

If you're using application/x-www-form-urlencoded or multipart/form-data, you can safely call context.Request.ReadFormAsync() multiple times as it returns a cached instance on subsequent calls.

If you're using a different content type, you'll have to manually buffer the request and replace the request body by a rewindable stream like MemoryStream. Here's how you could do using an inline middleware (you need to register it soon in your pipeline):

app.Use(next => async context => {     // Keep the original stream in a separate     // variable to restore it later if necessary.     var stream = context.Request.Body;      // Optimization: don't buffer the request if     // there was no stream or if it is rewindable.     if (stream == Stream.Null || stream.CanSeek)     {         await next(context);          return;     }      try     {         using (var buffer = new MemoryStream())         {             // Copy the request stream to the memory stream.             await stream.CopyToAsync(buffer);              // Rewind the memory stream.             buffer.Position = 0L;              // Replace the request stream by the memory stream.             context.Request.Body = buffer;              // Invoke the rest of the pipeline.             await next(context);         }     }      finally     {         // Restore the original stream.         context.Request.Body = stream;     } }); 

You can also use the BufferingHelper.EnableRewind() extension, which is part of the Microsoft.AspNet.Http package: it's based on a similar approach but relies on a special stream that starts buffering data in memory and spools everything to a temp file on disk when the threshold is reached:

app.Use(next => context => {     context.Request.EnableRewind();      return next(context); }); 

FYI: a buffering middleware will probably be added to vNext in the future.

like image 130
Kévin Chalet Avatar answered Sep 19 '22 13:09

Kévin Chalet