J'essaie de lire le corps de la requête dans la OnActionExecuting
méthode, mais j'obtiens toujours null
le corps.
var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();
J'ai essayé de définir explicitement la position du flux sur 0, mais cela n'a pas non plus fonctionné. Puisqu'il s'agit d'ASP.NET CORE, les choses sont un peu différentes, je pense. Je peux voir tous les exemples ici faisant référence aux anciennes versions de webapi.
Y a-t-il une autre façon de faire cela?
c#
asp.net-web-api
asp.net-core
Kasun Koswattha
la source
la source
Réponses:
Dans ASP.Net Core, il semble compliqué de lire plusieurs fois la requête de corps, mais si votre première tentative le fait correctement, vous devriez être bien pour les prochaines tentatives.
J'ai lu plusieurs retournements par exemple en remplaçant le flux corporel, mais je pense que ce qui suit est le plus propre:
Les points les plus importants étant
[ÉDITER]
Comme le souligne Murad, vous pouvez également profiter de l'extension .Net Core 2.1:
EnableBuffering
elle stocke les requêtes volumineuses sur le disque au lieu de les garder en mémoire, évitant ainsi les problèmes de gros flux stockés en mémoire (fichiers, images, ...) . Vous pouvez modifier le dossier temporaire en définissantASPNETCORE_TEMP
la variable d'environnement et les fichiers sont supprimés une fois la demande terminée.Dans un AuthorizationFilter , vous pouvez effectuer les opérations suivantes:
Ensuite, vous pouvez à nouveau utiliser le corps dans le gestionnaire de requêtes.
Dans votre cas, si vous obtenez un résultat nul, cela signifie probablement que le corps a déjà été lu à un stade antérieur. Dans ce cas, vous devrez peut-être utiliser un middleware (voir ci-dessous).
Attention toutefois si vous gérez des flux volumineux, ce comportement implique que tout est chargé en mémoire, cela ne doit pas être déclenché en cas de téléchargement de fichier.
Vous voudrez peut-être l'utiliser comme middleware
Le mien ressemble à ceci (encore une fois, si vous téléchargez / téléchargez des fichiers volumineux, cela devrait être désactivé pour éviter les problèmes de mémoire):
la source
req.EnableRewind();
? J'utilise le code ci-dessus et cela fonctionne bien.request.EnableBuffering()
(wrapper overEnableRewind()
) Il est disponible dans ASP.NET Core 2.1 docs.microsoft.com/en-us/dotnet/api/…Une solution plus claire, fonctionne dans ASP.Net Core 2.1 / 3.1
Classe de filtre
Dans un contrôleur
la source
.EnableRewind()
AuthorizeAttribute
àAttribute
(dans ASP.Net Core 3.1).Pour pouvoir rembobiner le corps de la requête, la réponse de @ Jean m'a aidé à trouver une solution qui semble bien fonctionner. J'utilise actuellement ceci pour le middleware Global Exception Handler mais le principe est le même.
J'ai créé un middleware qui permet essentiellement le rembobinage sur le corps de la requête (au lieu d'un décorateur).
Cela peut ensuite être utilisé dans votre
Startup.cs
comme ainsi:En utilisant cette approche, j'ai pu rembobiner le flux du corps de la requête avec succès.
la source
UseEnableRequestRewind(this IApplicationBuilder builder)
.C'est un peu un vieux fil de discussion, mais depuis que je suis arrivé ici, je me suis dit que je publierais mes résultats afin qu'ils puissent aider les autres.
Tout d'abord, j'ai eu le même problème, où je voulais obtenir le Request.Body et faire quelque chose avec ça (journalisation / audit). Mais sinon, je voulais que le point final ait le même aspect.
Donc, il semblait que l'appel EnableBuffering () pourrait faire l'affaire. Ensuite, vous pouvez faire une recherche (0, xxx) sur le corps et relire le contenu, etc.
Cependant, cela a conduit à mon prochain numéro. J'obtiendrais des exceptions «Les opérations synchrones sont interdites» lors de l'accès au point final. Donc, la solution de contournement consiste à définir la propriété AllowSynchronousIO = true, dans les options. Il existe un certain nombre de façons d'accomplir cela (mais il n'est pas important de détailler ici.)
ALORS, le problème suivant est que lorsque je vais lire la requête, le corps a déjà été éliminé. Pouah. Alors, qu'est-ce qui donne?
J'utilise Newtonsoft.JSON comme analyseur [FromBody] dans l'appel endpiont. C'est ce qui est responsable des lectures synchrones et cela ferme également le flux une fois terminé. Solution? Lire le flux avant de passer à l'analyse JSON? Bien sûr, cela fonctionne et je me suis retrouvé avec ceci:
Alors maintenant, je peux accéder au corps en utilisant le HttpContext.Items ["request_body"] dans les points de terminaison qui ont l'attribut [ReadRequestBodyIntoItems].
Mais mec, cela semble être beaucoup trop de cerceaux à franchir. Alors, voici où j'ai terminé, et j'en suis vraiment content.
Mon point de terminaison a commencé comme quelque chose comme:
Mais il est beaucoup plus simple de simplement changer la signature, comme ceci:
J'ai vraiment aimé cela car il ne lit qu'une seule fois le flux corporel et j'ai le contrôle de la désérialisation. Bien sûr, c'est bien si ASP.NET core fait cette magie pour moi, mais ici je ne perds pas de temps à lire le flux deux fois (peut-être en tamponnant à chaque fois), et le code est assez clair et propre.
Si vous avez besoin de cette fonctionnalité sur de nombreux points de terminaison, peut-être que les approches middleware pourraient être plus propres, ou vous pouvez au moins encapsuler l'extraction de corps dans une fonction d'extension pour rendre le code plus concis.
Quoi qu'il en soit, je n'ai trouvé aucune source qui aborde les 3 aspects de ce problème, d'où cet article. Espérons que cela aide quelqu'un!
BTW: cela utilisait ASP .NET Core 3.1.
la source
J'ai eu un problème similaire lors de l'utilisation d'ASP.NET Core 2.1:
SaoBiz
avoir signalé cette solution.Donc, la solution évidente est de permettre à la demande d'être rembobinable, mais assurez-vous qu'après lecture du corps, la liaison fonctionne toujours.
EnableRequestRewindMiddleware
Startup.cs
(placez-le au début de la méthode Configure)
Un autre middleware
Cela fait partie du middleware qui nécessite de décompresser les informations POSTées pour vérifier des éléments.
la source
Récemment, je suis tombé sur une solution très élégante qui prend en JSON aléatoire dont vous n'avez aucune idée de la structure:
C'est aussi simple que ça.
la source
La
IHttpContextAccessor
méthode fonctionne si vous souhaitez emprunter cette voie.TLDR;
Injectez le
IHttpContextAccessor
Rembobiner -
HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
Lis --
System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body); JObject asObj = JObject.Parse(sr.ReadToEnd());
Plus - Une tentative d'exemple concis et non compilant des éléments dont vous devrez vous assurer qu'ils sont en place afin d'obtenir un fichier utilisable
IHttpContextAccessor
. Les réponses ont indiqué correctement que vous devrez revenir au début lorsque vous essayez de lire le corps de la requête. LesCanSeek
,Position
propriétés sur le flux corps de la demande utile pour vérifier cela.Documentation .NET Core DI
la source
J'ai pu lire le corps de la requête dans une application asp.net core 3.1 comme celle-ci (avec un middleware simple qui permet la mise en mémoire tampon - le rembobinage activable semble fonctionner pour les versions antérieures de .Net Core-):
la source
pour lire
Body
, vous pouvez lire de manière asynchrone.utilisez la
async
méthode comme suit:Test avec le facteur:
Cela fonctionne bien et testé en
Asp.net core
version2.0 , 2.1 , 2.2, 3.0
.J'espère que c'est utile.
la source
Je voulais également lire le Request.Body sans le mapper automatiquement à un modèle de paramètre d'action. Testé de nombreuses façons différentes avant de résoudre ce problème. Et je n'ai pas trouvé de solution de travail décrite ici. Cette solution est actuellement basée sur le framework .NET Core 3.0.
reader.readToEnd () cousu comme une manière simple, même s'il était compilé, il lançait une exception d'exécution qui m'obligeait à utiliser un appel asynchrone. Donc, à la place, j'ai utilisé ReadToEndAsync (), mais cela fonctionnait parfois, et parfois non. Me donnant des erreurs comme, impossible de lire après la fermeture du flux. Le problème est que nous ne pouvons pas garantir qu'il retournera le résultat dans le même thread (même si nous utilisons l'attente). Nous avons donc besoin d'une sorte de rappel. Cette solution a fonctionné pour moi.
la source
La manière la plus simple de procéder est la suivante:
Dans la méthode Controller dont vous devez extraire le corps, ajoutez ce paramètre: [FromBody] SomeClass value
Déclarez "SomeClass" comme: class SomeClass {chaîne publique SomeParameter {get; ensemble; }}
Lorsque le corps brut est envoyé en json, .net core sait le lire très facilement.
la source
À ceux qui veulent simplement obtenir le contenu (corps de la requête) de la requête:
Utilisez l'
[FromBody]
attribut dans le paramètre de méthode de votre contrôleur.Comme le dit doc: cet attribut spécifie qu'un paramètre ou une propriété doit être lié à l'aide du corps de la requête.
la source
Un moyen rapide d'ajouter la mise en mémoire tampon des réponses dans .NET Core 3.1 est
dans Startup.cs. J'ai trouvé que cela garantit également que la mise en mémoire tampon sera activée avant la lecture du flux, ce qui était un problème pour .Net Core 3.1 avec certaines des autres réponses de filtre middleware / d'autorisation que j'ai vues.
Ensuite, vous pouvez lire le corps de votre requête via
HttpContext.Request.Body
dans votre gestionnaire comme plusieurs autres l'ont suggéré.Il convient également de prendre en
EnableBuffering
compte les surcharges qui vous permettent de limiter la quantité de mémoire tampon en mémoire avant d'utiliser un fichier temporaire, ainsi qu'une limite globale de votre mémoire tampon. NB si une requête dépasse cette limite une exception sera levée et la requête n'atteindra jamais votre gestionnaire.la source