2012-08-24 14 views
12

Al tratar de un objeto en una acción en un controlador esporádicamente parece ser nulo. Descubrí que se debe al ReadAsStringAsync() en la anulación SendAsync() del DelegatingHandler. El problema es con el contenido. Cuando mi cliente envía un cuerpo de contenido y se lee en el registrador nunca es leído por Controller Action Invoker (o puede estar en algún lugar en el JsonFormatter). Sospecho que la llamada subsiguiente al Content.ReadAsStringAsync() no arroja una excepción pero tampoco devuelve el cuerpo de contenido esperado (se devuelve cierta información que indica que la lectura asíncrona se ha completado).HttpRequestMessage.Content se pierde cuando se lee en un registro DelegatingHandler en ASP.Net Web API

Pero mi problema persiste ya que quiero leer un parámetro [FromBody] en una acción y es nulo cuando la RaceCondition de Content.ReadStringAsync se gana por el DelegatingHandler. Sin embargo, cuando JsonFormatter lo gana, obtengo el objeto, pero eso es raro (solo al inicio del servicio).

Aquí es mi DelegatingHandler código:

public class LogHandler : DelegatingHandler 
{ 

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     var apiRequest = new WebApiUsageRequest(request); 
     WriteLog(apiRequest); 
     request.Content.ReadAsStringAsync().ContinueWith(t => 
     { 
      apiRequest.Content = t.Result; 
      WriteLog(apiRequest); 
     }); 

     return base.SendAsync(request, cancellationToken).ContinueWith(task => 
     { 
      var apiResponse = new WebApiUsageResponse(task.Result); 
      apiResponse.Content = task.Result.Content != null ? task.Result.Content.ReadAsStringAsync().Result : null; 
      WriteLog(apiResponse); 
      return task.Result; 
     }); 
    } 
} 

¿Alguien tiene una pista para la solución de este problema?

+0

Olvidé mencionar que este es RC. Sospecho que la observación permanece igual en RTM también – Sando

Respuesta

9

Esto es por diseño. En ASP.NET Web API, el contenido del cuerpo se trata como una transmisión de solo reenvío que solo se puede leer una vez.

Usted puede tratar de utilizar ASP.NET Web API Tracing pero no he probarlo con solicitud POST sin embargo, así que no estoy seguro de cómo/si está trazando el cuerpo de la petición (que está trazando parámetros de petición GET sin lugar a duda). Puede leer más aquí:

+2

Gracias.Creo que para mis requisitos puedo vivir sin escribir el contenido para iniciar sesión. Sin embargo, esto debería ser un 'Punto a tener en cuenta' para todos los desarrolladores de API web que intenten registrar los contenidos y también que utilicen [De cuerpo] en Acciones POST – Sando

2

pero si se utiliza el código de abajo en el SendAsync funciona correctamente

 if (request.Content != null) 
     { 
      request.Content.ReadAsByteArrayAsync().ContinueWith 
       (
        (task) => 
        { 

          var xxx = System.Text.UTF8Encoding.UTF8.GetString(task.Result); 
        }); 
     } 
     return base.SendAsync(request, cancellationToken) //than call the base 

. . .

+0

. Pero, ¿por qué funciona al hacer esto? –

+0

Eso no es lo mismo. Estás leyendo el contenido de la solicitud, no el contenido de la respuesta, que por cierto también es el motivo por el que está trabajando. – Adam

5

El método ReadAsStreamAsync devuelve el contenido del cuerpo.

var body = string.Empty; 
using (var reader = new StreamReader(request.Content.ReadAsStreamAsync().Result)) 
{ 
    reader.BaseStream.Seek(0, SeekOrigin.Begin); 
    body = reader.ReadToEnd(); 
} 
+0

Ten en cuenta que el bloque que utiliza cerrará el vapor subyacente. – ivanmartinvalle

1

Esto funcionó para mí:

using (var stream = new MemoryStream()) 
{ 
    var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; 
    context.Request.InputStream.Seek(0, SeekOrigin.Begin); 
    context.Request.InputStream.CopyTo(stream); 
    string requestBody = Encoding.UTF8.GetString(stream.ToArray()); 
} 

devuelto para mí la representación JSON de mi objeto de parámetro, así que lo puedan utilizar para el manejo de excepciones y la explotación forestal.

encontrado como respuesta aceptada here

+0

Pero aquí no podemos recibir encabezados de solicitud –

1

Esto es lo que terminé haciendo:

public string SafelyReadContent(HttpRequestMessage request) 
{ 
    var stream = request.Content.ReadAsStreamAsync().Result; 
    var reader = new StreamReader(stream); 
    var result = reader.ReadToEnd(); 
    stream.Seek(0, SeekOrigin.Begin); 

    return result; 
} 

@ respuesta de pirimoglu de utilizar un "uso" de bloque no funcionó para mí, ya que cuando se dispuso el lector , la transmisión subyacente también se cerró.

+0

no funciona :( –

Cuestiones relacionadas