Read request body twice
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.
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();
...
}