Estoy tratando de leer el cuerpo de la solicitud en el OnActionExecuting
método, pero siempre obtengo null
el cuerpo.
var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();
Intenté establecer explícitamente la posición de la transmisión en 0, pero eso tampoco funcionó. Dado que esto es ASP.NET CORE, las cosas son un poco diferentes, creo. Puedo ver todas las muestras aquí que se refieren a versiones antiguas de webapi.
¿Hay otra manera de hacer esto?
c#
asp.net-web-api
asp.net-core
Kasun Koswattha
fuente
fuente
Respuestas:
En ASP.Net Core parece complicado leer varias veces la solicitud del cuerpo, sin embargo, si su primer intento lo hace de la manera correcta, debería estar bien para los próximos intentos.
Leí varios cambios, por ejemplo, sustituyendo el flujo del cuerpo, pero creo que el siguiente es el más limpio:
Los puntos más importantes son
[EDITAR]
Como señaló Murad, también puede aprovechar la extensión .Net Core 2.1:
EnableBuffering
almacena solicitudes grandes en el disco en lugar de mantenerlas en la memoria, evitando problemas de flujos grandes almacenados en la memoria (archivos, imágenes, ...) . Puede cambiar la carpeta temporal configurandoASPNETCORE_TEMP
la variable de entorno, y los archivos se eliminan una vez que finaliza la solicitud.En un AuthorizationFilter , puede hacer lo siguiente:
Luego, puede usar el cuerpo nuevamente en el controlador de solicitudes.
En su caso, si obtiene un resultado nulo, probablemente significa que el cuerpo ya se ha leído en una etapa anterior. En ese caso, es posible que deba utilizar un software intermedio (consulte a continuación).
Sin embargo, tenga cuidado si maneja flujos grandes, ese comportamiento implica que todo está cargado en la memoria, esto no debería activarse en caso de que se cargue un archivo.
Es posible que desee utilizar esto como Middleware
El mío se ve así (nuevamente, si descarga / carga archivos grandes, esto debería estar desactivado para evitar problemas de memoria):
fuente
req.EnableRewind();
? Utilizo el código anterior y funciona bien.request.EnableBuffering()
(envoltorioEnableRewind()
) Está disponible en ASP.NET Core 2.1 docs.microsoft.com/en-us/dotnet/api/…Una solución más clara, funciona en ASP.Net Core 2.1 / 3.1
Clase de filtro
En un controlador
fuente
.EnableRewind()
AuthorizeAttribute
aAttribute
(en ASP.Net Core 3.1).Para poder rebobinar el cuerpo de la solicitud, la respuesta de @ Jean me ayudó a encontrar una solución que parece funcionar bien. Actualmente lo uso para el Middleware del controlador de excepciones globales, pero el principio es el mismo.
Creé un middleware que básicamente permite el rebobinado en el cuerpo de la solicitud (en lugar de un decorador).
Esto luego se puede usar a su
Startup.cs
gusto, así:Usando este enfoque, he podido rebobinar el flujo del cuerpo de la solicitud con éxito.
fuente
UseEnableRequestRewind(this IApplicationBuilder builder)
.Este es un hilo un poco antiguo, pero desde que llegué aquí, pensé que publicaría mis hallazgos para que puedan ayudar a otros.
Primero, tuve el mismo problema, donde quería obtener el Request.Body y hacer algo con eso (registro / auditoría). Pero, por lo demás, quería que el punto final tuviera el mismo aspecto.
Entonces, parecía que la llamada EnableBuffering () podría hacer el truco. Luego puede hacer una búsqueda (0, xxx) en el cuerpo y volver a leer el contenido, etc.
Sin embargo, esto me llevó a mi próximo número. Obtendría excepciones de "Las operaciones sincronizadas no están permitidas" al acceder al punto final. Entonces, la solución alternativa es establecer la propiedad AllowSynchronousIO = true, en las opciones. Hay varias formas de lograr esto (pero no es importante detallar aquí ...)
ENTONCES, el siguiente problema es que cuando voy a leer la Solicitud, el cuerpo ya se ha eliminado. Ugh. Entonces, ¿qué pasa?
Estoy usando Newtonsoft.JSON como mi analizador [FromBody] en la llamada endpiont. Eso es lo que es responsable de las lecturas sincrónicas y también cierra la secuencia cuando está lista. ¿Solución? ¿Leer la transmisión antes de que llegue al análisis JSON? Claro, eso funciona y terminé con esto:
Así que ahora puedo acceder al cuerpo usando HttpContext.Items ["request_body"] en los puntos finales que tienen el atributo [ReadRequestBodyIntoItems].
Pero hombre, esto parece demasiados obstáculos para saltar. Así que aquí es donde terminé, y estoy realmente feliz con eso.
Mi punto final comenzó como algo como:
Pero es mucho más sencillo simplemente cambiar la firma, así:
Realmente me gustó esto porque solo lee el flujo del cuerpo una vez y yo tengo el control de la deserialización. Claro, es bueno si el núcleo de ASP.NET hace esta magia por mí, pero aquí no pierdo el tiempo leyendo la transmisión dos veces (quizás almacenando en búfer cada vez), y el código es bastante claro y limpio.
Si necesita esta funcionalidad en muchos puntos finales, quizás los enfoques de middleware podrían ser más limpios, o al menos puede encapsular la extracción del cuerpo en una función de extensión para hacer que el código sea más conciso.
De todos modos, no encontré ninguna fuente que tocara los 3 aspectos de este problema, de ahí esta publicación. ¡Ojalá esto ayude a alguien!
Por cierto: esto estaba usando ASP .NET Core 3.1.
fuente
Tuve un problema similar al usar ASP.NET Core 2.1:
SaoBiz
por señalar esta solución.Entonces, la solución obvia es permitir que la solicitud sea rebobinada, pero asegúrese de que después de leer el cuerpo, el enlace aún funcione.
EnableRequestRewindMiddleware
Startup.cs
(coloque esto al principio del método Configure)
Algún otro middleware
Esto es parte del middleware que requiere desempaquetar la información POST para verificar cosas.
fuente
Recientemente me encontré con una solución muy elegante que toma JSON aleatorio de la que no tienes idea de la estructura:
Así de fácil.
fuente
El
IHttpContextAccessor
método funciona si desea seguir esta ruta.TLDR;
Inyectar el
IHttpContextAccessor
Rebobinar -
HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
Leer -
System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body); JObject asObj = JObject.Parse(sr.ReadToEnd());
Más : un intento de un ejemplo conciso y no compilable de los elementos que debe asegurarse de que estén en su lugar para obtener un archivo utilizable
IHttpContextAccessor
. Las respuestas han señalado correctamente que deberá volver al principio cuando intente leer el cuerpo de la solicitud. Las propiedadesCanSeek
,Position
en el flujo del cuerpo de la solicitud son útiles para verificar esto..NET Core DI Docs
fuente
Pude leer el cuerpo de la solicitud en una aplicación asp.net core 3.1 como esta (junto con un middleware simple que permite el almacenamiento en búfer -el rebobinado parece funcionar para versiones anteriores de .Net Core-):
fuente
para leer
Body
, puede leer de forma asincrónica.use el
async
método como sigue:Prueba con cartero:
Está funcionando bien y probado en
Asp.net core
versión2.0 , 2.1 , 2.2, 3.0
.Espero sea de utilidad.
fuente
También quería leer Request.Body sin asignarlo automáticamente a algún modelo de parámetro de acción. Probado de muchas formas diferentes antes de resolver esto. Y no encontré ninguna solución de trabajo descrita aquí. Esta solución se basa actualmente en el marco .NET Core 3.0.
reader.readToEnd () se asentó como una forma simple, a pesar de que se compiló, arrojó una excepción de tiempo de ejecución que requería que usara una llamada asíncrona. Entonces, en su lugar, usé ReadToEndAsync (), sin embargo, a veces funcionó y otras no. Dándome errores como, no se puede leer después de cerrar la transmisión. El problema es que no podemos garantizar que devolverá el resultado en el mismo hilo (incluso si usamos el await). Entonces necesitamos algún tipo de devolución de llamada. Esta solución funcionó para mí.
fuente
La forma más sencilla posible de hacerlo es la siguiente:
En el método Controller del que necesita extraer el cuerpo, agregue este parámetro: [FromBody] Valor de SomeClass
Declare "SomeClass" como: class SomeClass {cadena pública SomeParameter {get; conjunto; }}
Cuando el cuerpo en bruto se envía como json, .net core sabe cómo leerlo muy fácilmente.
fuente
Para aquellos que simplemente quieren obtener el contenido (cuerpo de la solicitud) de la solicitud:
Utilice el
[FromBody]
atributo en el parámetro de método de su controlador.Como dice el documento: este atributo especifica que un parámetro o propiedad debe vincularse utilizando el cuerpo de la solicitud.
fuente
Una forma rápida de agregar búfer de respuesta en .NET Core 3.1 es
en Startup.cs. Descubrí que esto también garantiza que el almacenamiento en búfer se habilitará antes de que se lea la transmisión, lo que fue un problema para .Net Core 3.1 con algunas de las otras respuestas de filtro de autorización / middleware que he visto.
Luego, puede leer el cuerpo de su solicitud a través
HttpContext.Request.Body
de su controlador, como varios otros han sugerido.También vale la pena considerar que
EnableBuffering
tiene sobrecargas que le permiten limitar la cantidad de búfer en la memoria antes de que use un archivo temporal, y también un límite general para su búfer. Nota: si una solicitud excede este límite, se lanzará una excepción y la solicitud nunca llegará a su administrador.fuente