Registro de mensajes de solicitud / respuesta cuando se usa HttpClient

114

Tengo un método que hace un POST como el siguiente

var response = await client.PostAsJsonAsync(url, entity);

if (response.IsSuccessStatusCode)
{
        // read the response as strongly typed object
        return await response.Content.ReadAsAsync<T>();
}

Mi pregunta es cómo puedo obtener el JSON real que se publicó desde el objeto de la entidad. Me gustaría registrar el JSON que se publica, por lo que será bueno tenerlo sin tener que serializar un json.

govin
fuente

Respuestas:

196

Un ejemplo de cómo podrías hacer esto:

Algunas notas:

  • LoggingHandlerintercepta la solicitud antes de que la maneje y HttpClientHandlerfinalmente escribe en el cable.

  • PostAsJsonAsyncLa extensión crea internamente un ObjectContenty cuando ReadAsStringAsync()se llama en el LoggingHandler, hace que el formateador interno ObjectContentserialice el objeto y esa es la razón por la que está viendo el contenido en json.

Controlador de registro:

public class LoggingHandler : DelegatingHandler
{
    public LoggingHandler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Console.WriteLine("Request:");
        Console.WriteLine(request.ToString());
        if (request.Content != null)
        {
            Console.WriteLine(await request.Content.ReadAsStringAsync());
        }
        Console.WriteLine();

        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        Console.WriteLine("Response:");
        Console.WriteLine(response.ToString());
        if (response.Content != null)
        {
            Console.WriteLine(await response.Content.ReadAsStringAsync());
        }
        Console.WriteLine();

        return response;
    }
}

Encadena el LoggingHandler anterior con HttpClient :

HttpClient client = new HttpClient(new LoggingHandler(new HttpClientHandler()));
HttpResponseMessage response = client.PostAsJsonAsync(baseAddress + "/api/values", "Hello, World!").Result;

Salida:

Request:
Method: POST, RequestUri: 'http://kirandesktop:9095/api/values', Version: 1.1, Content: System.Net.Http.ObjectContent`1[
[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], Headers:
{
  Content-Type: application/json; charset=utf-8
}
"Hello, World!"

Response:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Date: Fri, 20 Sep 2013 20:21:26 GMT
  Server: Microsoft-HTTPAPI/2.0
  Content-Length: 15
  Content-Type: application/json; charset=utf-8
}
"Hello, World!"
Kiran Challa
fuente
3
Eso es bueno si necesita los detalles de la solicitud, pero no consigue enviar la solicitud exacta al servidor. Si necesita precisamente todo el byte enviado al servidor, no funcionará de esta manera.
mathk
1
¿Por qué el new HttpClientHandler()? No está presente en los documentos oficiales: docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/…
Zero3
1
Ah, aparentemente se requiere no obtener una excepción acerca de que el controlador interno es nulo ...
Zero3
3
También puede anular MessageProcessingHandler que pide básicamente una ProcessRequesty ProcessResponsemétodo para usted antes y después de la SendAsyncllamada.
IllusiveBrian
1
La respuesta de @ RamiA a continuación es mejor, porque no requiere cambios de código. Una vez que haya terminado de depurar, elimine el seguimiento de su configuración, y eso es todo. No es necesario hacer una nueva construcción.
Tsahi Asher
50

Ver http://mikehadlow.blogspot.com/2012/07/tracing-systemnet-to-debug-http-clients.html

Para configurar un oyente System.Net para que se genere tanto en la consola como en un archivo de registro, agregue lo siguiente a su archivo de configuración de ensamblaje:

<system.diagnostics>
  <trace autoflush="true" />
  <sources>
    <source name="System.Net">
      <listeners>
        <add name="MyTraceFile"/>
        <add name="MyConsole"/>
      </listeners>
    </source>
  </sources>
  <sharedListeners>
    <add
      name="MyTraceFile"
      type="System.Diagnostics.TextWriterTraceListener"
      initializeData="System.Net.trace.log" />
    <add name="MyConsole" type="System.Diagnostics.ConsoleTraceListener" />
  </sharedListeners>
  <switches>
    <add name="System.Net" value="Verbose" />
  </switches>
</system.diagnostics>
Rami A.
fuente
2
esta es una gran solución, gracias por investigar un poco y compartir.
Piwaf
Como funciona ? Copié <system.diagnostics>en app.configdebajo, <configuration>pero en la bincarpeta no hay un archivo de registro y la salida de la consola tampoco muestra nada, ¿qué me falta?
Muflix
1
@Muflix, puede leer la documentación que está vinculada en la página a la que se hace referencia en la parte superior de mi respuesta. Creo que el nombre de archivo especificado en el initializeDataatributo se creará en el directorio de trabajo actual del ejecutable que está ejecutando, por lo que es posible que desee verificar qué ruta se encuentra en su entorno.
Rami A.
11

El rastreo de red también está disponible para los siguientes objetos (consulte el artículo sobre msdn )

  • System.Net.Sockets Algunos métodos públicos de las clases Socket, TcpListener, TcpClient y Dns
  • System.Net Algunos métodos públicos de las clases HttpWebRequest, HttpWebResponse, FtpWebRequest y FtpWebResponse, e información de depuración SSL (certificados no válidos, lista de emisores faltantes y errores de certificado de cliente).
  • System.Net.HttpListener Algunos métodos públicos de las clases HttpListener, HttpListenerRequest y HttpListenerResponse.
  • System.Net.Cache Algunos métodos privados e internos en System.Net.Cache.
  • System.Net.Http Algunos métodos públicos de las clases HttpClient, DelegatingHandler, HttpClientHandler, HttpMessageHandler, MessageProcessingHandler y WebRequestHandler.
  • System.Net.WebSockets.WebSocket Algunos métodos públicos de las clases ClientWebSocket y WebSocket.

Coloque las siguientes líneas de código en el archivo de configuración

<configuration>  
  <system.diagnostics>  
    <sources>  
      <source name="System.Net" tracemode="includehex" maxdatasize="1024">  
        <listeners>  
          <add name="System.Net"/>  
        </listeners>  
      </source>  
      <source name="System.Net.Cache">  
        <listeners>  
          <add name="System.Net"/>  
        </listeners>  
      </source>  
      <source name="System.Net.Http">  
        <listeners>  
          <add name="System.Net"/>  
        </listeners>  
      </source>  
      <source name="System.Net.Sockets">  
        <listeners>  
          <add name="System.Net"/>  
        </listeners>  
      </source>  
      <source name="System.Net.WebSockets">  
        <listeners>  
          <add name="System.Net"/>  
        </listeners>  
      </source>  
    </sources>  
    <switches>  
      <add name="System.Net" value="Verbose"/>  
      <add name="System.Net.Cache" value="Verbose"/>  
      <add name="System.Net.Http" value="Verbose"/>  
      <add name="System.Net.Sockets" value="Verbose"/>  
      <add name="System.Net.WebSockets" value="Verbose"/>  
    </switches>  
    <sharedListeners>  
      <add name="System.Net"  
        type="System.Diagnostics.TextWriterTraceListener"  
        initializeData="network.log"  
      />  
    </sharedListeners>  
    <trace autoflush="true"/>  
  </system.diagnostics>  
</configuration>  
StuS
fuente
-14

La solución más sencilla sería utilizar Wireshark y rastrear el flujo HTTP tcp.

usuario1096164
fuente
9
Imagínese un mundo donde la mayoría de este tipo de conexiones son en realidad HTTPS.
traste