web-dev-qa-db-fra.com

RestSharp imprimer les en-têtes de demande et de réponse bruts

J'utilise RestSharp pour effectuer des appels vers un service Web. Tout va bien, mais je me demandais s'il serait possible d'imprimer les en-têtes et le corps de demande bruts qui sont envoyés et les en-têtes de réponse bruts et le corps de réponse qui revient.

C'est mon code où je crée une demande et j'obtiens une réponse

public static TResponse ExecutePostCall<TResponse, TRequest>(String url, TRequest requestData, string token= "") where TResponse : new()
{
    RestRequest request = new RestRequest(url, Method.POST);
    if (!string.IsNullOrWhiteSpace(token))
    {
        request.AddHeader("TOKEN", token);
    }


    request.RequestFormat = DataFormat.Json;
    request.AddBody(requestData);

    // print raw request here

    var response = _restClient.Execute<TResponse>(request);

    // print raw response here

    return response.Data;
}

serait-il possible d'imprimer la demande et la réponse brutes?

49
Professor Chaos

Comme nous le savons déjà, RestSharp ne fournit pas de mécanisme pour atteindre exactement ce que vous voulez et l'activation du traçage .Net est un peu exagérant IMO.

À des fins de journalisation (débogage) (quelque chose que je peux laisser activé pendant un certain temps dans PROD par exemple), j'ai trouvé cette approche très utile (même si elle contient quelques détails sur la façon de l'appeler, lisez ci-dessous le code):

private void LogRequest(IRestRequest request, IRestResponse response, long durationMs)
{
        var requestToLog = new
        {
            resource = request.Resource,
            // Parameters are custom anonymous objects in order to have the parameter type as a Nice string
            // otherwise it will just show the enum value
            parameters = request.Parameters.Select(parameter => new
            {
                name = parameter.Name,
                value = parameter.Value,
                type = parameter.Type.ToString()
            }),
            // ToString() here to have the method as a Nice string otherwise it will just show the enum value
            method = request.Method.ToString(),
            // This will generate the actual Uri used in the request
            uri = _restClient.BuildUri(request),
        };

        var responseToLog = new
        {
            statusCode = response.StatusCode,
            content = response.Content,
            headers = response.Headers,
            // The Uri that actually responded (could be different from the requestUri if a redirection occurred)
            responseUri = response.ResponseUri,
            errorMessage = response.ErrorMessage,
        };

        Trace.Write(string.Format("Request completed in {0} ms, Request: {1}, Response: {2}",
                durationMs, 
                JsonConvert.SerializeObject(requestToLog),
                JsonConvert.SerializeObject(responseToLog)));
}

À noter:

  • Les en-têtes, segments d'URL, paramètres QueryString, corps, etc. sont tous considérés comme des paramètres pour RestSharp, tous ceux qui apparaissent dans la collection de paramètres de la demande, avec leur type correspondant.
  • La méthode de journalisation doit être appelée APRÈS la demande. Cela est nécessaire en raison du fonctionnement de RestSharp, la méthode Execute ajoutera des en-têtes, exécutera les authentificateurs (si certains sont configurés), etc. et tout cela modifiera la demande. Ainsi, pour que tous les paramètres réels envoyés soient enregistrés, la méthode Execute aurait dû être appelée avant de consigner la demande.
  • RestSharp lui-même ne lancera jamais (à la place, les erreurs sont enregistrées dans la propriété response.ErrorException), mais je pense que la désérialisation pourrait lancer (pas sûr) et en plus, je devais enregistrer la réponse brute, j'ai donc choisi d'implémenter ma propre désérialisation.
  • Gardez à l'esprit que RestSharp utilise sa propre mise en forme lors de la conversion des valeurs de paramètres pour générer l'URI, donc la sérialisation des paramètres pour les enregistrer peut ne pas montrer exactement les mêmes choses qui ont été mises dans l'URI. C'est pourquoi la méthode IRestClient.BuildUri Est assez cool pour obtenir l'URI réellement appelé (y compris l'URL de base, les segments d'URL remplacés, les paramètres queryString ajoutés, etc.).
  • EDIT: Gardez également à l'esprit qu'il pourrait arriver que le sérialiseur que RestSharp utilise pour le corps ne soit pas le même que ce code utilise, donc je suppose que le code pourrait être ajusté pour utiliser request.JsonSerializer.Serialize() pour le rendu du paramètre body (je n'ai pas essayé).
  • Un code personnalisé était nécessaire pour obtenir des descriptions de Nice dans les journaux des valeurs d'énumérations.
  • StopWatch l'utilisation pourrait être déplacée pour inclure la désérialisation dans la mesure.

Voici un exemple de base de classe de base complète avec journalisation (à l'aide de NLog):

using System;
using System.Diagnostics;
using System.Linq;
using NLog;
using Newtonsoft.Json;
using RestSharp;

namespace Apis
{
    public abstract class RestApiBase
    {
        protected readonly IRestClient _restClient;
        protected readonly ILogger _logger;

        protected RestApiBase(IRestClient restClient, ILogger logger)
        {
            _restClient = restClient;
            _logger = logger;
        }

        protected virtual IRestResponse Execute(IRestRequest request)
        {
            IRestResponse response = null;
            var stopWatch = new Stopwatch();

            try
            {
                stopWatch.Start();
                response = _restClient.Execute(request);
                stopWatch.Stop();

                // CUSTOM CODE: Do more stuff here if you need to...

                return response;
            }
            catch (Exception e)
            {
                // Handle exceptions in your CUSTOM CODE (restSharp will never throw itself)
            }
            finally
            {
                LogRequest(request, response, stopWatch.ElapsedMilliseconds);
            }

            return null;
        }

        protected virtual T Execute<T>(IRestRequest request) where T : new()
        {
            IRestResponse response = null;
            var stopWatch = new Stopwatch();

            try
            {
                stopWatch.Start();
                response = _restClient.Execute(request);
                stopWatch.Stop();

                // CUSTOM CODE: Do more stuff here if you need to...

                // We can't use RestSharp deserialization because it could throw, and we need a clean response
                // We need to implement our own deserialization.
                var returnType = JsonConvert.DeserializeObject<T>(response.Content);
                return returnType;
            }
            catch (Exception e)
            {
                // Handle exceptions in your CUSTOM CODE (restSharp will never throw itself)
                // Handle exceptions in deserialization
            }
            finally
            {
                LogRequest(request, response, stopWatch.ElapsedMilliseconds);
            }

            return default(T);
        }

        private void LogRequest(IRestRequest request, IRestResponse response, long durationMs)
        {
            _logger.Trace(() =>
            {
                var requestToLog = new
                {
                    resource = request.Resource,
                    // Parameters are custom anonymous objects in order to have the parameter type as a Nice string
                    // otherwise it will just show the enum value
                    parameters = request.Parameters.Select(parameter => new
                    {
                        name = parameter.Name,
                        value = parameter.Value,
                        type = parameter.Type.ToString()
                    }),
                    // ToString() here to have the method as a Nice string otherwise it will just show the enum value
                    method = request.Method.ToString(),
                    // This will generate the actual Uri used in the request
                    uri = _restClient.BuildUri(request),
                };

                var responseToLog = new
                {
                    statusCode = response.StatusCode,
                    content = response.Content,
                    headers = response.Headers,
                    // The Uri that actually responded (could be different from the requestUri if a redirection occurred)
                    responseUri = response.ResponseUri,
                    errorMessage = response.ErrorMessage,
                };

                return string.Format("Request completed in {0} ms, Request: {1}, Response: {2}",
                    durationMs, JsonConvert.SerializeObject(requestToLog),
                    JsonConvert.SerializeObject(responseToLog));
            });
        }
    }
}

Cette classe enregistrera quelque chose comme ceci (assez formaté pour être collé ici):

Request completed in 372 ms, Request : {
    "resource" : "/Event/Create/{hostId}/{startTime}",
    "parameters" : [{
            "name" : "hostId",
            "value" : "116644",
            "type" : "UrlSegment"
        }, {
            "name" : "startTime",
            "value" : "2016-05-18T19:48:58.9744911Z",
            "type" : "UrlSegment"
        }, {
            "name" : "application/json",
            "value" : "{\"durationMinutes\":720,\"seats\":100,\"title\":\"Hello StackOverflow!\"}",
            "type" : "RequestBody"
        }, {
            "name" : "api_key",
            "value" : "123456",
            "type" : "QueryString"
        }, {
            "name" : "Accept",
            "value" : "application/json, application/xml, text/json, text/x-json, text/javascript, text/xml",
            "type" : "HttpHeader"
        }
    ],
    "method" : "POST",
    "uri" : "http://127.0.0.1:8000/Event/Create/116644/2016-05-18T19%3A48%3A58.9744911Z?api_key=123456"
}, Response : {
    "statusCode" : 200,
    "content" : "{\"eventId\":2000045,\"hostId\":116644,\"scheduledLength\":720,\"seatsReserved\":100,\"startTime\":\"2016-05-18T19:48:58.973Z\"",
    "headers" : [{
            "Name" : "Access-Control-Allow-Origin",
            "Value" : "*",
            "Type" : 3
        }, {
            "Name" : "Access-Control-Allow-Methods",
            "Value" : "POST, GET, OPTIONS, PUT, DELETE, HEAD",
            "Type" : 3
        }, {
            "Name" : "Access-Control-Allow-Headers",
            "Value" : "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept",
            "Type" : 3
        }, {
            "Name" : "Access-Control-Max-Age",
            "Value" : "1728000",
            "Type" : 3
        }, {
            "Name" : "Content-Length",
            "Value" : "1001",
            "Type" : 3
        }, {
            "Name" : "Content-Type",
            "Value" : "application/json",
            "Type" : 3
        }, {
            "Name" : "Date",
            "Value" : "Wed, 18 May 2016 17:44:16 GMT",
            "Type" : 3
        }
    ],
    "responseUri" : "http://127.0.0.1:8000/Event/Create/116644/2016-05-18T19%3A48%3A58.9744911Z?api_key=123456",
    "errorMessage" : null
}

Espérant que ceci puisse t'être utile!

50
LucasMetal

.net fournit sa propre fonction de journalisation, pourtant puissante. Cela peut être activé via le fichier de configuration.

J'ai trouvé cette astuce ici . John Sheehan a indiqué Comment: configurer le traçage résea article. (une note: j'ai édité la configuration fournie, désactivé la journalisation de bas niveau inutile (pour moi)).

  <system.diagnostics>
    <sources>
      <source name="System.Net" tracemode="protocolonly" 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>
    </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>
25
akava

Je viens de trouver le code ci-dessous dans les exemples RestSharp. Il vous permet d'imprimer votre réponse brute.

client.ExecuteAsync(request, response =>
                   {
                       Console.WriteLine(response.Content);
                   });
7
Jiongfeng Luo

Vous devez parcourir le request.Parameters liste et formatez-le en une chaîne dans le format que vous voulez.

var sb = new StringBuilder();
foreach(var param in request.Parameters)
{
    sb.AppendFormat("{0}: {1}\r\n", param.Name, param.Value);
}
return sb.ToString();

Si vous souhaitez que la sortie affiche les en-têtes de demande, puis le corps similaire à Fiddler, il vous suffit de classer la collection par en-têtes de demande, puis par corps de demande. L'objet Parameter de la collection a une énumération de paramètre Type.

5
The Muffin Man

Vous pouvez utiliser Fiddler pour capturer les requêtes HTTP.

4
Neshta

Une option est d'utiliser votre propre authentificateur. RestSharp permet d'injecter un authentificateur:

var client = new RestClient();
client.Authenticator = new YourAuthenticator(); // implements IAuthenticator

public interface IAuthenticator
{
    void Authenticate(IRestClient client, IRestRequest request);
}

internal class YourAuthenticator: IAuthenticator
{
  public void Authenticate(IRestClient client, IRestRequest request)
  {
    // log request
  }
}

La méthode Authenticate de l'authentificateur est la toute première chose appelée lors de l'appel à RestClient.Execute ou RestClient.Execute. La méthode Authenticate passe la RestRequest en cours d'exécution vous donnant accès à toutes les parties des données de la demande (en-têtes, paramètres, etc.) à partir du wiki de RestSharp

Cela signifie que dans la méthode Authenticate, vous pouvez enregistrer la demande.

1
giganoide

Comme solution partielle, vous pouvez utiliser la méthode BuildUri de RestClient:

var response = client.Execute(request);
if (response.StatusCode != HttpStatusCode.OK)
    throw new Exception($"Failed to send request: {client.BuildUri(request)}");
0
starteleport