【发布时间】:2016-12-03 12:49:26
【问题描述】:
我正在尝试记录所有转到服务引用的出站请求,包括完整的请求和响应正文。我以为我有一个使用 behaviorExtensions 的解决方案,但是在部署之后,很明显扩展是在多个请求之间共享的。
这是我当前的代码:
public class LoggingBehaviorExtender : BehaviorExtensionElement
{
public override Type BehaviorType => typeof(LoggingRequestExtender);
protected override object CreateBehavior() { return new LoggingRequestExtender(); }
}
public class LoggingRequestExtender : IClientMessageInspector, IEndpointBehavior
{
public string Request { get; private set; }
public string Response { get; private set; }
#region IClientMessageInspector
public virtual object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
Request = request.ToString();
Response = null;
return null;
}
public virtual void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
Response = reply.ToString();
}
#endregion
#region IEndpointBehavior
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
#endregion
}
然后,当我到达记录点时,我提取行为......
var lre = client.Endpoint.Behaviors.OfType<LoggingRequestExtender>().FirstOrDefault();
var req = lre?.Request;
var resp = lre?.Response;
在 LoggingRequestExtender 中添加调试日志,我发现它只针对多个请求实例化一次。
有没有办法确保这个行为类为每个线程都实例化了?或者在进行服务调用时是否有更好的方法来获取完整的请求/响应正文?
编辑/部分回答:
自从写这篇文章以来,我发现 BeforeSendRequest 返回的值作为相关状态传递给 AfterReceiveReply,因此我可以使用 guid 连接请求和响应:
public virtual object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
var guid = Guid.NewGuid();
WebServiceLog.LogCallStart(guid, channel.RemoteAddress.ToString(), request.ToString());
return guid;
}
public virtual void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
Guid guid = (Guid)correlationState;
WebServiceLog.LogCallEnd(guid, reply.ToString());
}
我发现这种方法有两个缺陷。一个是宜居的,它需要一个日志插入然后更新,而不是单个插入。
第二个问题更大:在出现异常(例如超时)的情况下,我们从未点击 AfterRecieveSupply,因此日志不知道发生了什么。我可以单独记录异常...
try
{
response = client.SomeFunction(request);
}
catch (Exception ex)
{
AppLog.Error("Some function failed", ex);
}
...但我看不到在 BeforeSendRequest / AfterReceiveReply 之外访问 guid 的方法,所以我没有任何东西可以将异常日志与服务请求日志联系起来。
【问题讨论】:
标签: c# web-services wcf logging