I'm using RestSharp
to make calls to a webservice. All is well but I was wondering if it would be possible to print the raw request headers and body that is sent out and the raw response headers and the response body that comes back.
This is my code where I create a request and get a response back
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; }
so, Would it be possible to print the raw request and response?
Type: HttpHeader Using LINQ: string userId = response. Headers . Where(x => x.Name == "userId") .
var client = new RestClient("http://localhost"); var request = new RestRequest("resource", Method. POST); request. AddParameter("auth_token", "1234"); request. AddBody(json); var response = client.
RestSharp is a comprehensive, open-source HTTP client library that works with all kinds of DotNet technologies. It can be used to build robust applications by making it easy to interface with public APIs and quickly access data without the complexity of dealing with raw HTTP requests.
RestSharp doesn't provide a mechanism to achieve exactly what you want and activating the .Net tracing is a bit overkilling IMO.
For logging (debugging) purposes (something that I can leave turned on for a while in PROD for example) I have found this approach to be very useful (although it has some details on how to call it, read below the 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))); }
Things to note:
IRestClient.BuildUri
method it's pretty cool to get the actually called Uri (including the base url, the replaced url segments, the added queryString parameters, etc).request.JsonSerializer.Serialize()
for rendering the body parameter (I haven't tried this).StopWatch
usage could be moved around to include deserialization in the measuring. Here it is a basic complete base class example with logging (using 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)); }); } } }
This class will log something like this (pretty formatted for pasting here):
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 }
Hope you find this useful!
.net provides its own yet powerful logging feature. This can be turned on via config file.
I found this tip here. John Sheehan pointed to How to: Configure Network Tracing article. (a note: I edited the config provided, turned off unnecessary (for me) low level logging).
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With