2015-07-13 18 views
6

Ich versuche, den Körper in einer Middleware zu Authentifizierungszwecken zu lesen, aber wenn die Anfrage an den API-Controller kommt, ist das Objekt leer, da der Text bereits gelesen wurde. Gibt es das überhaupt? Ich lese den Körper so in meiner Middleware.Anforderung Körper zweimal lesen

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

Nur neugierig, warum liest du den Körper des Antrags, wenn die Authentifizierung durchführen? –

+0

Es ist eine API, wo die Anfrage zum Beispiel ApiKey auch beim Aufbau der Antwort und auch ein Hash benötigt wird, um die Anfrage zu sichern. Was macht keinen Sinn in den Kopfzeilen zu sein. –

+0

Ein [Beispiel] (http://stackoverflow.com/questions/42561350/read-json-post-data-in-asp-net-core-mvc/42922579#42922579) von PinPoint EnableRewind verwenden, um Json von Körper zu lesen. –

Antwort

14

Wenn Sie application/x-www-form-urlencoded oder multipart/form-data verwenden, können Sie sicher nennen context.Request.ReadFormAsync() mehrere Male, da es eine zwischengespeicherte Instanz bei nachfolgenden Aufrufen zurückgibt.

Wenn Sie einen anderen Inhaltstyp verwenden, müssen Sie die Anforderung manuell puffern und den Anfragetext durch einen zurückspulbaren Stream wie MemoryStream ersetzen. Hier ist, wie Sie tun können, eine Inline-Middleware (Sie müssen es bald in Ihrer Pipeline registrieren):

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; 
    } 
}); 

Sie können auch die BufferingHelper.EnableRewind() Erweiterung verwenden, die einen Teil des Microsoft.AspNet.Http Paket ist: es basiert auf einem ähnlichen Ansatz sondern stützt sich auf einen speziellen Strom, der Pufferung von Daten im Speicher beginnt und Spulen alles in eine temporäre Datei auf der Festplatte, wenn der Schwellenwert erreicht ist:

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

    return next(context); 
}); 

FYI: eine Puffermiddleware wird wahrscheinlich zu vNext in der Zukunft hinzugefügt werden.

+2

zu lesen Ich bin neugierig auf das Caching. Sollte sich dieser Teil des Vertrags oder der Implementierungsdetails in Zukunft ändern? –

+1

@Pinpoint Danke, dass ich nicht daran denke, ist eine gute Idee. –

+0

@SimonBelanger in naher Zukunft, Hosts und Middleware wird wahrscheinlich einen gemeinsamen Vertrag teilen, um anzugeben, ob sie Pufferung unterstützen oder nicht. Weitere Informationen finden Sie auf dieser Wiki-Seite für weitere Informationen: https://github.com/aspnet/HttpAbstractions/wiki/Rolling-Notes – Pinpoint

3

Verwendung für PinPoint Erwähnung von 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() 
... 
} 

Dann in Ihrer Middleware einfach zurückspulen und wieder gelesen

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