我使用RestSharp
来调用网络服务。一切都很好,但我想知道是否可以打印发出的原始请求标题和正文以及原始响应标题和返回的响应正文。
这是我创建请求并获得回复的代码
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;
}
那么,是否可以打印原始请求和响应?
答案 0 :(得分:48)
正如我们已经知道的那样,RestSharp并没有提供一种机制来实现你想要的,并且激活.Net跟踪有点过分使用IMO。
为了记录(调试)目的(例如我可以在PROD中保留一段时间)我发现这种方法非常有用(虽然它有一些关于如何调用它的细节,请阅读下面的代码):
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)));
}
需要注意的事项:
IRestClient.BuildUri
方法获得实际调用的Uri(包括基本URL,替换的url段,添加的queryString参数等)非常酷的原因。request.JsonSerializer.Serialize()
使用以包括测量中的反序列化。 这是一个基本的完整基类示例,带有日志记录(使用NLog):
StopWatch
这个类会记录这样的东西(格式很适合粘贴):
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));
});
}
}
}
希望你觉得这很有用!
答案 1 :(得分:24)
.net提供了自己强大的日志记录功能。这可以通过配置文件打开。
我找到了这个提示here。约翰希恩指出How to: Configure Network Tracing文章。 (注意:我编辑了提供的配置,关闭了不必要的(对我来说)低级别的日志记录)。
<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>
答案 2 :(得分:5)
我刚刚在RestSharp示例中找到了以下代码。它允许您打印原始响应。
client.ExecuteAsync(request, response =>
{
Console.WriteLine(response.Content);
});
答案 3 :(得分:5)
您必须遍历request.Parameters
列表并将其格式化为您喜欢的任何格式的字符串。
var sb = new StringBuilder();
foreach(var param in request.Parameters)
{
sb.AppendFormat("{0}: {1}\r\n", param.Name, param.Value);
}
return sb.ToString();
如果您希望输出显示请求标题,然后是类似于Fiddler的正文,您只需按Request标题排序集合,然后按Request body排序。集合中的Parameter
对象具有Type
参数枚举。
答案 4 :(得分:1)
一个选项是使用您自己的身份验证器。 RestSharp允许注入身份验证器:
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
}
}
身份验证者的Authenticate方法是第一件事 在调用RestClient.Execute或RestClient.Execute时。的 传递身份验证方法,当前正在执行的RestRequest 使您可以访问请求数据的各个部分(标题, 参数等) from RestSharp's wiki
这意味着您可以在Authenticate方法中记录请求。
答案 5 :(得分:0)
作为部分解决方案,您可以使用RestClient的BuildUri
方法:
var response = client.Execute(request);
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception($"Failed to send request: {client.BuildUri(request)}");
答案 6 :(得分:-2)
您可以尝试使用
Trace.WriteLine(request.JsonSerializer.Serialize(request));
获取请求和
response.Content(); // as Luo have suggested
请求与Fiddler显示的不一样,但它包含所有数据且可读(最后有一些RestSharp垃圾)。