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?
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:
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.).request.JsonSerializer.Serialize()
pour le rendu du paramètre body (je n'ai pas essayé).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!
.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>
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);
});
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
.
Vous pouvez utiliser Fiddler pour capturer les requêtes HTTP.
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.
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)}");