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 re
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.
This works with .Net Core 2.1 and higher.
Today I run in a similar issue. Long story short, what used to work with
Body.Seek(0, SeekOrigin.Begin);
resulted in today in exception, at least in my case. This happened after the code was migrated to the latest version of .NET Core.
The workaround for me was to add this:
app.Use(next => context => { context.Request.EnableBuffering(); return next(context);
Add this before setting up controllers or MVC. This seems to be added as part of the .NET Core 2.1 version.
Hope this helps someone!
Cheers and happy coding.
Usage for 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 just rewind and reread
private async Task GenerateToken(HttpContext context)
{
context.Request.EnableRewind();
string jsonData = new StreamReader(context.Request.Body).ReadToEnd();
...
}