webapi pelicula net microsoft cantante aspnet asp asp.net .net asp.net-web-api owin owin-middleware

asp.net - net - owin pelicula



Rebobinar la secuencia del cuerpo de la solicitud (3)

Estoy volviendo a implementar un registrador de solicitudes como Owin Middleware, que registra la URL de solicitud y el cuerpo de todas las solicitudes entrantes. Puedo leer el cuerpo, pero si lo hago, el parámetro body en mi controlador es nulo.

Supongo que es nulo porque la posición del flujo está al final, por lo que no queda nada por leer cuando intenta deserializar el cuerpo. Tuve un problema similar en una versión anterior de Web API, pero pude volver a establecer la posición de Stream en 0. Esta secuencia en particular arroja una excepción This stream does not support seek operations .

En la versión más reciente de Web API 2.0 podía llamar a Request.HttpContent.ReadAsStringAsync() dentro de mi registrador de solicitudes, y el cuerpo aún llegaría al controlador con tacto.

¿Cómo puedo rebobinar la secuencia después de leerla?

o

¿Cómo puedo leer el cuerpo de la solicitud sin consumirlo?

public class RequestLoggerMiddleware : OwinMiddleware { public RequestLoggerMiddleware(OwinMiddleware next) : base(next) { } public override Task Invoke(IOwinContext context) { return Task.Run(() => { string body = new StreamReader(context.Request.Body).ReadToEnd(); // log body context.Request.Body.Position = 0; // cannot set stream position back to 0 Console.WriteLine(context.Request.Body.CanSeek); // prints false this.Next.Invoke(context); }); } }

public class SampleController : ApiController { public void Post(ModelClass body) { // body is now null if the middleware reads it } }


Acabo de encontrar una solución. Reemplazar la transmisión original con una nueva transmisión que contenga los datos.

public override Task Invoke(IOwinContext context) { return Task.Run(() => { string body = new StreamReader(context.Request.Body).ReadToEnd(); // log body byte[] requestData = Encoding.UTF8.GetBytes(body); context.Request.Body = new MemoryStream(requestData); this.Next.Invoke(context); }); }

Si está tratando con grandes cantidades de datos, estoy seguro de que FileStream también funcionará como reemplazo.


Aquí hay una pequeña mejora a la primera respuesta de Despertar, que me ayudó mucho, pero me encontré con un problema cuando trabajaba con datos binarios. El paso intermedio de extraer la secuencia en una cadena y volver a colocarla en una matriz de bytes utilizando Encoding.UTF8.GetBytes(body) confunde el contenido binario (el contenido cambiará a menos que sea una cadena codificada en UTF8). Aquí está mi solución usando Stream.CopyTo() :

public override async Task Invoke(IOwinContext context) { // read out body (wait for all bytes) using (var streamCopy = new MemoryStream()) { context.Request.Body.CopyTo(streamCopy); streamCopy.Position = 0; // rewind string body = new StreamReader(streamCopy).ReadToEnd(); // log body streamCopy.Position = 0; // rewind again context.Request.Body = streamCopy; // put back in place for downstream handlers await this.Next.Invoke(context); } }

Además, MemoryStream es agradable porque puedes verificar la longitud de la secuencia antes de registrar todo el cuerpo (que es algo que no quiero hacer en caso de que alguien cargue un archivo enorme).


Sé que esto es viejo, pero solo para ayudar a cualquiera que se encuentre con esto. Necesitas buscar en la transmisión: context.Request.Body.Seek(0, SeekOrigin.Begin);