Protokollieren von Anforderungs- / Antwortnachrichten bei Verwendung von HttpClient

114

Ich habe eine Methode, die einen POST wie unten ausführt

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

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

Meine Frage ist, wie ich den tatsächlichen JSON erhalten kann, der vom Entitätsobjekt gebucht wurde. Ich möchte den JSON protokollieren, der VERÖFFENTLICHT wird, daher ist es schön, das zu haben, ohne dass ich selbst eine JSON-Serialisierung durchführen muss.

govin
quelle

Antworten:

196

Ein Beispiel dafür, wie Sie dies tun können:

Einige Notizen:

  • LoggingHandlerfängt die Anforderung ab, bevor sie verarbeitet wird, HttpClientHandlerund schreibt schließlich in die Leitung.

  • PostAsJsonAsyncDie Erweiterung erstellt intern ein ObjectContentund wenn sie ReadAsStringAsync()in aufgerufen wird LoggingHandler, bewirkt sie, dass der Formatierer im Inneren ObjectContentdas Objekt serialisiert. Aus diesem Grund wird der Inhalt in json angezeigt.

Protokollierungshandler:

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;
    }
}

Verketten Sie den obigen LoggingHandler mit HttpClient :

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

Ausgabe:

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
quelle
3
Das ist schön, wenn Sie die Anforderungsdetails benötigen, die genaue Anforderung jedoch nicht an den Server gesendet werden kann. Wenn Sie genau das gesamte Byte benötigen, das an den Server gesendet wird, funktioniert dies nicht.
Mathk
1
Warum das new HttpClientHandler()? Es ist nicht in den offiziellen Dokumenten enthalten: docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/…
Zero3
1
Ah, es ist anscheinend erforderlich, keine Ausnahme zu bekommen, dass der innere Handler null ist ...
Zero3
3
Sie können auch MessageProcessingHandler überschreiben, der im Grunde eine ProcessRequestund ProcessResponse-Methode für Sie vor und nach dem SendAsyncAufruf aufruft .
IllusiveBrian
1
Die Antwort von @ RamiA unten ist besser, da keine Codeänderungen erforderlich sind. Sobald Sie mit dem Debuggen fertig sind, entfernen Sie die Ablaufverfolgung aus Ihrer Konfiguration, und das war's. Sie müssen keinen neuen Build erstellen.
Tsahi Asher
50

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

Fügen Sie Ihrer Assembly-Konfigurationsdatei Folgendes hinzu, um einen System.Net-Listener für die Ausgabe sowohl an die Konsole als auch an eine Protokolldatei zu konfigurieren:

<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.
quelle
2
Dies ist eine großartige Lösung. Vielen Dank, dass Sie einige Nachforschungen angestellt und geteilt haben.
Piwaf
Wie funktioniert es ? Ich habe <system.diagnostics>in app.configunter kopiert, <configuration>aber im binOrdner gibt es keine Protokolldatei und die Konsolenausgabe zeigt auch nichts an. Was fehlt mir?
Muflix
1
@Muflix, Sie können die Dokumentation lesen, die auf der Seite verlinkt ist, auf die oben in meiner Antwort verwiesen wird. Ich denke, der im initializeDataAttribut angegebene Dateiname wird im aktuellen Arbeitsverzeichnis der ausführbaren Datei erstellt, die Sie ausführen. Daher möchten Sie möglicherweise überprüfen, welcher Pfad sich in Ihrer Umgebung befindet.
Rami A.
11

Netzwerk-Tracing auch für nächste Objekte verfügbar (siehe Artikel auf msdn )

  • System.Net.Sockets Einige öffentliche Methoden der Klassen Socket, TcpListener, TcpClient und Dns
  • System.Net Einige öffentliche Methoden der Klassen HttpWebRequest, HttpWebResponse, FtpWebRequest und FtpWebResponse sowie SSL-Debuginformationen (ungültige Zertifikate, Liste fehlender Aussteller und Clientzertifikatsfehler).
  • System.Net.HttpListener Einige öffentliche Methoden der Klassen HttpListener, HttpListenerRequest und HttpListenerResponse.
  • System.Net.Cache Einige private und interne Methoden in System.Net.Cache.
  • System.Net.Http Einige öffentliche Methoden der Klassen HttpClient, DelegatingHandler, HttpClientHandler, HttpMessageHandler, MessageProcessingHandler und WebRequestHandler.
  • System.Net.WebSockets.WebSocket Einige öffentliche Methoden der Klassen ClientWebSocket und WebSocket.

Fügen Sie die nächsten Codezeilen in die Konfigurationsdatei ein

<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
quelle
-14

Die einfachste Lösung wäre, Wireshark zu verwenden und den HTTP-TCP-Fluss zu verfolgen.

user1096164
quelle
8
Stellen Sie sich eine Welt vor, in der die meisten dieser Verbindungstypen tatsächlich HTTPS sind.
Bund