Ich versuche, den Anfragetext in der OnActionExecuting
Methode zu lesen , aber ich bekomme immer null
für den Text.
var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();
Ich habe versucht, die Stream-Position explizit auf 0 zu setzen, aber das hat auch nicht funktioniert. Da dies ASP.NET CORE ist, sind die Dinge meiner Meinung nach etwas anders. Ich kann alle Beispiele hier sehen, die sich auf alte Webapi-Versionen beziehen.
Gibt es eine andere Möglichkeit, dies zu tun?
c#
asp.net-web-api
asp.net-core
Kasun Koswattha
quelle
quelle
Antworten:
In ASP.Net Core scheint es kompliziert zu sein, die Textanforderung mehrmals zu lesen. Wenn Ihr erster Versuch es jedoch richtig macht, sollten Sie für die nächsten Versuche in Ordnung sein.
Ich habe mehrere Turnarounds gelesen, indem ich zum Beispiel den Body Stream ersetzt habe, aber ich denke, das Folgende ist das sauberste:
Die wichtigsten Punkte sind
[BEARBEITEN]
Wie von Murad hervorgehoben, können Sie auch die Erweiterung .Net Core 2.1 nutzen:
EnableBuffering
Sie speichert große Anforderungen auf der Festplatte, anstatt sie im Speicher zu belassen, und vermeidet Probleme mit großen Streams, die im Speicher gespeichert sind (Dateien, Bilder, ...). . Sie können den temporären Ordner ändern, indem Sie dieASPNETCORE_TEMP
Umgebungsvariable festlegen. Die Dateien werden gelöscht, sobald die Anforderung beendet ist.In einem AuthorizationFilter können Sie Folgendes tun:
Anschließend können Sie den Body im Request-Handler erneut verwenden.
Wenn Sie in Ihrem Fall ein Nullergebnis erhalten, bedeutet dies wahrscheinlich, dass der Körper bereits zu einem früheren Zeitpunkt gelesen wurde. In diesem Fall müssen Sie möglicherweise eine Middleware verwenden (siehe unten).
Seien Sie jedoch vorsichtig, wenn Sie mit großen Streams umgehen. Dieses Verhalten impliziert, dass alles in den Speicher geladen wird. Dies sollte bei einem Datei-Upload nicht ausgelöst werden.
Möglicherweise möchten Sie dies als Middleware verwenden
Meins sieht folgendermaßen aus (wenn Sie große Dateien herunterladen / hochladen, sollte dies deaktiviert werden, um Speicherprobleme zu vermeiden):
quelle
req.EnableRewind();
? Ich benutze den obigen Code und es funktioniert gut.request.EnableBuffering()
(Wrapper überEnableRewind()
). Es ist in ASP.NET Core 2.1 docs.microsoft.com/en-us/dotnet/api/…Eine klarere Lösung funktioniert in ASP.Net Core 2.1 / 3.1
Filterklasse
In einem Controller
quelle
.EnableRewind()
AuthorizeAttribute
zuAttribute
(in ASP.Net Core 3.1).Um den Anfragetext zurückspulen zu können, hat mir die Antwort von @ Jean geholfen, eine Lösung zu finden, die anscheinend gut funktioniert. Ich verwende dies derzeit für Global Exception Handler Middleware, aber das Prinzip ist das gleiche.
Ich habe eine Middleware erstellt, die im Grunde das Zurückspulen auf dem Anforderungshauptteil ermöglicht (anstelle eines Dekorateurs).
Dies kann dann
Startup.cs
wie folgt verwendet werden:Mit diesem Ansatz konnte ich den Anforderungskörperstrom erfolgreich zurückspulen.
quelle
UseEnableRequestRewind(this IApplicationBuilder builder)
.Dies ist ein bisschen wie ein alter Thread, aber seit ich hier bin, dachte ich, ich würde meine Ergebnisse veröffentlichen, damit sie anderen helfen können.
Erstens hatte ich das gleiche Problem, bei dem ich den Request.Body abrufen und etwas damit anfangen wollte (Protokollierung / Überwachung). Ansonsten wollte ich, dass der Endpunkt gleich aussieht.
Es schien also, als würde der Aufruf von EnableBuffering () den Trick machen. Dann können Sie eine Suche (0, xxx) am Körper durchführen und den Inhalt usw. erneut lesen.
Dies führte jedoch zu meiner nächsten Ausgabe. Beim Zugriff auf den Endpunkt werden Ausnahmen "Synchornous-Operationen sind nicht zulässig" angezeigt. Die Problemumgehung besteht darin, die Eigenschaft AllowSynchronousIO = true in den Optionen festzulegen. Es gibt eine Reihe von Möglichkeiten, um dies zu erreichen (aber nicht wichtig, um hier näher darauf einzugehen ..)
DANN ist das nächste Problem, dass, wenn ich die Anfrage lese, sie bereits entsorgt wurde. Pfui. Also, was gibt es?
Ich verwende Newtonsoft.JSON als meinen [FromBody] -Parser im Endpiont-Aufruf. Das ist es, was für die synchronen Lesevorgänge verantwortlich ist und es schließt auch den Stream, wenn es fertig ist. Lösung? Lesen Sie den Stream, bevor er zum JSON-Parsing gelangt? Klar, das funktioniert und ich bin dazu gekommen:
Jetzt kann ich mit HttpContext.Items ["request_body"] in den Endpunkten mit dem Attribut [ReadRequestBodyIntoItems] auf den Body zugreifen.
Aber Mann, das scheint viel zu viele Reifen zu sein, um durch zu springen. Hier habe ich also geendet und bin sehr zufrieden damit.
Mein Endpunkt begann wie folgt:
Es ist jedoch viel einfacher, die Signatur wie folgt zu ändern:
Das hat mir sehr gut gefallen, weil es den Körperstrom nur einmal liest und ich die Kontrolle über die Deserialisierung habe. Sicher, es ist schön, wenn der ASP.NET-Kern diese Magie für mich ausführt, aber hier verschwende ich keine Zeit damit, den Stream zweimal zu lesen (möglicherweise jedes Mal zu puffern), und der Code ist ziemlich klar und sauber.
Wenn Sie diese Funktionalität auf vielen Endpunkten benötigen, sind die Middleware-Ansätze möglicherweise sauberer, oder Sie können die Körperextraktion zumindest in eine Erweiterungsfunktion einkapseln, um den Code präziser zu gestalten.
Wie auch immer, ich habe keine Quelle gefunden, die alle drei Aspekte dieser Ausgabe berührt hat, daher dieser Beitrag. Hoffentlich hilft das jemandem!
Übrigens: Dies war mit ASP .NET Core 3.1.
quelle
Ich hatte ein ähnliches Problem bei der Verwendung von ASP.NET Core 2.1:
SaoBiz
für den Hinweis auf diese Lösung.Die naheliegende Lösung besteht also darin, das Zurückspulen der Anforderung zuzulassen. Stellen Sie jedoch sicher, dass die Bindung nach dem Lesen des Körpers weiterhin funktioniert.
EnableRequestRewindMiddleware
Startup.cs
(Platzieren Sie dies am Anfang der Configure-Methode.)
Eine andere Middleware
Dies ist Teil der Middleware, die das Entpacken der POST-Informationen zum Überprüfen von Daten erfordert.
quelle
Die
IHttpContextAccessor
Methode funktioniert, wenn Sie diesen Weg gehen möchten.TLDR;
Injizieren Sie die
IHttpContextAccessor
Rücklauf -
HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
Lesen --
System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body); JObject asObj = JObject.Parse(sr.ReadToEnd());
Mehr - Ein Versuch, ein präzises, nicht kompiliertes Beispiel für die Elemente zu erstellen, die Sie sicherstellen müssen, damit sie verwendet werden können
IHttpContextAccessor
. Die Antworten haben richtig darauf hingewiesen, dass Sie zum Versuch zurückkehren müssen, den Anfragetext zu lesen. DieCanSeek
,Position
Eigenschaften auf der Anfrage Körper strömen hilfreich dies für die Überprüfung..NET Core DI-Dokumente
quelle
Ich konnte den Anforderungshauptteil in einer asp.net Core 3.1-Anwendung wie dieser lesen (zusammen mit einer einfachen Middleware, die das Puffern ermöglicht - das Aktivieren des Zurückspulens scheint für frühere .Net Core-Versionen zu funktionieren-):
quelle
Kürzlich bin ich auf eine sehr elegante Lösung gestoßen, die zufälliges JSON berücksichtigt, von dem Sie keine Ahnung haben, wie es aufgebaut ist:
So einfach ist das.
quelle
Zum Lesen
Body
können Sie asynchron lesen.Verwenden Sie die
async
Methode wie folgt:Test mit Postbote:
Es funktioniert gut und wurde in der
Asp.net core
Version getestet2.0 , 2.1 , 2.2, 3.0
.Ich hoffe es ist nützlich.
quelle
Ich wollte auch den Request.Body lesen, ohne ihn automatisch einem Aktionsparameter-Modell zuzuordnen. Viele verschiedene Möglichkeiten getestet, bevor dies gelöst wurde. Und ich habe keine hier beschriebene funktionierende Lösung gefunden. Diese Lösung basiert derzeit auf dem .NET Core 3.0-Framework.
reader.readToEnd () wurde auf einfache Weise gesäumt, obwohl es kompiliert wurde, löste es eine Laufzeitausnahme aus, bei der ich einen asynchronen Aufruf verwenden musste. Also habe ich stattdessen ReadToEndAsync () verwendet, aber es hat manchmal funktioniert und manchmal nicht. Gib mir Fehler wie, kann nicht lesen, nachdem der Stream geschlossen wurde. Das Problem ist, dass wir nicht garantieren können, dass das Ergebnis im selben Thread zurückgegeben wird (selbst wenn wir das Warten verwenden). Wir brauchen also eine Art Rückruf. Diese Lösung hat bei mir funktioniert.
quelle
Der einfachste Weg, dies zu tun, ist der folgende:
Fügen Sie in der Controller-Methode, aus der Sie den Body extrahieren müssen, diesen Parameter hinzu: [FromBody] SomeClass-Wert
Deklarieren Sie die "SomeClass" als: class SomeClass {public string SomeParameter {get; einstellen; }}
Wenn der Rohkörper als JSON gesendet wird, kann der .net-Kern ihn sehr einfach lesen.
quelle
Für diejenigen, die einfach den Inhalt (Anfragetext) aus der Anfrage erhalten möchten:
Verwenden Sie das
[FromBody]
Attribut in Ihrem Controller-Methodenparameter.Wie doc sagt: Dieses Attribut gibt an, dass ein Parameter oder eine Eigenschaft mithilfe des Anforderungshauptteils gebunden werden soll.
quelle
Eine schnelle Möglichkeit, die Antwortpufferung in .NET Core 3.1 hinzuzufügen, ist
in Startup.cs. Ich fand, dass dies auch garantiert, dass die Pufferung aktiviert wird, bevor der Stream gelesen wurde, was ein Problem für .Net Core 3.1 mit einigen der anderen Antworten auf Middleware- / Autorisierungsfilter war, die ich gesehen habe.
Dann können Sie Ihren Anfragetext über
HttpContext.Request.Body
in Ihrem Handler lesen, wie mehrere andere vorgeschlagen haben.Erwägenswert ist auch, dass
EnableBuffering
es Überladungen gibt, mit denen Sie die Pufferung im Speicher begrenzen können, bevor eine temporäre Datei verwendet wird, sowie eine Gesamtbeschränkung für Ihren Puffer. Hinweis: Wenn eine Anforderung dieses Limit überschreitet, wird eine Ausnahme ausgelöst und die Anforderung erreicht niemals Ihren Handler.quelle