En ASP.Net Core, il semble compliqué de lire plusieurs fois le corps de la requête, cependant si votre première tentative le fait de la bonne manière, vous devriez vous en sortir pour les tentatives suivantes.
J'ai lu plusieurs retournements de situation, par exemple en substituant le flux du corps, mais je pense que le suivant est le plus propre :
Les points les plus importants étant
- pour indiquer à la demande que vous lirez son corps deux fois ou plus,
- de ne pas fermer le flux du corps, et
- pour le rembobiner à sa position initiale afin que le processus interne ne se perde pas.
[EDIT]
Comme l'a souligné Murad, vous pouvez également tirer parti de l'extension .Net Core 2.1 : EnableBuffering
Il stocke les grosses requêtes 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 changer le dossier temporaire en définissant ASPNETCORE_TEMP
et les fichiers sont supprimés dès que la demande est terminée.
Dans un AuthorizationFilter vous pouvez faire ce qui suit :
// Helper to enable request stream rewinds
using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableBodyRewind : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var bodyStr = "";
var req = context.HttpContext.Request;
// Allows using several time the stream in ASP.Net Core
req.EnableRewind();
// Arguments: Stream, Encoding, detect encoding, buffer size
// AND, the most important: keep stream opened
using (StreamReader reader
= new StreamReader(req.Body, Encoding.UTF8, true, 1024, true))
{
bodyStr = reader.ReadToEnd();
}
// Rewind, so the core is not lost when it looks the body for the request
req.Body.Position = 0;
// Do whatever work with bodyStr here
}
}
public class SomeController : Controller
{
[HttpPost("MyRoute")]
[EnableBodyRewind]
public IActionResult SomeAction([FromBody]MyPostModel model )
{
// play the body string again
}
}
Vous pouvez ensuite réutiliser le corps dans le gestionnaire de demande.
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).
Cependant, faites attention si vous manipulez de grands flux, ce comportement implique que tout est chargé en mémoire, cela ne devrait pas être déclenché dans le cas d'un téléchargement de fichier.
Vous pouvez l'utiliser comme Middleware
Le mien ressemble à ceci (encore une fois, si vous téléchargez de gros fichiers, il faut désactiver cette fonction pour éviter les problèmes de mémoire) :
public sealed class BodyRewindMiddleware
{
private readonly RequestDelegate _next;
public BodyRewindMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try { context.Request.EnableRewind(); } catch { }
await _next(context);
// context.Request.Body.Dipose() might be added to release memory, not tested
}
}
public static class BodyRewindExtensions
{
public static IApplicationBuilder EnableRequestBodyRewind(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<BodyRewindMiddleware>();
}
}
8 votes
Attention, si le corps de la requête a déjà été lu avant pendant le pipeline de la requête, alors il est vide lorsque vous essayez de le lire une deuxième fois.
1 votes
Duplicata possible de Lire HttpContent dans le contrôleur WebApi
0 votes
@Fabio Merci pour l'info, peut-on définir la position et la relire ?
0 votes
@KasunKoswattha - Par conception, le contenu du corps du message est traité comme un flux de données à lecture seule qui ne peut être lu qu'une seule fois.
0 votes
Je suppose que la question vise plutôt les filtres ou les intergiciels que les contrôleurs.
0 votes
@JimAho J'ai pu résoudre ce problème en injectant le HttpContextAccessor de la classe de démarrage à mes contrôleurs. En utilisant HttpContextAccessor la requête entière peut être lue. L'événement dans le constructeur du contrôleur.
0 votes
Oui, j'en suis conscient, Kasun, mais je voulais savoir si le titre de la question prêtait à confusion. La question dit que vous lisez à l'intérieur
OnActionExecuting
qui est un filtre méthode, mais votre question vise contrôleur .