问题
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 );
    回答1:
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.
回答2:
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();
    ...
    }
    来源:https://stackoverflow.com/questions/31389781/read-request-body-twice