Read the request twice

I am trying to read the body in middleware for authentication purposes, but when the request hits the api controller, the object is empty because the body has already been read. Anyway, around this. I read 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 ); 
+6
asp.net-core asp.net-core-mvc asp.net-core-webapi
source share
2 answers

If you use application/x-www-form-urlencoded or multipart/form-data , you can safely call context.Request.ReadFormAsync() several times when it returns the cached instance on subsequent calls.

If you use a different type of content, you will have to manually buffer the request and replace the request body with a rewindable stream, such as a MemoryStream . Here you can use the built-in middleware (you need to register it 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 is based on a similar approach, but relies on a special thread that starts buffering data in memory and associates everything with a temporary file on disk when the threshold is reached :

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

FYI: In the future, vNext will add buffer middleware.

+15
source share

Using PinPoint's mention of EnableRewind

 Startup.cs using Microsoft.AspNetCore.Http.Internal; Startup.Configure(...){ ... //Its important the rewind us added before UseMvc app.Use(next => context => { context.Request.EnableRewind(); return next(context); }); app.UseMvc() ... } 

Then in your middleware, you simply rewind and re-read

 private async Task GenerateToken(HttpContext context) { context.Request.EnableRewind(); string jsonData = new StreamReader(context.Request.Body).ReadToEnd(); ... } 
+3
source share

All Articles