gpt4 book ai didi

c# - IEndpointBehavior 生命周期/记录服务调用

转载 作者:行者123 更新时间:2023-11-30 12:56:46 29 4
gpt4 key购买 nike

我正在尝试记录所有转到服务引用的出站请求,包括完整的请求和响应正文。我以为我有一个使用 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 返回的值作为 correlationState 传递给 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 的方法,所以我没有任何东西可以将异常日志绑定(bind)到服务请求日志。

最佳答案

有几种方法可以做到这一点。

1,您所描述的必须单独记录调用的情况不一定是那样。如果您的 WCF 服务位于非负载平衡服务器中,只需使用 Guid 作为键将请求添加到 MemoryCache。当请求进来时,然后取消请求并一次性登录。要捕获超时调用,您可以在线程上运行一个进程,该进程每 x 分钟检查一次 MemoryCache 以拉出并记录(使用足够的锁来确保线程安全)。

如果 WCF 服务处于负载平衡环境中,那么您所做的一切与上面相同,但存储到非 sql 类型的数据存储中。

2、外呼的代码是否在你的修改范围内?如果是这样,您可以放弃创建行为扩展,而是创建一个定制的消息记录器。使用实现 IDisposable 的类,您可以编写像这样的漂亮代码..

RequestMessage request = new RequestMessage();  
ResponseMessage response = null;

using (_messageLogger.LogMessage(request, () => response, CallContextHelper.GetContextId(), enabled))
{
response = _outboundService.DoSomething(request);
}

这将不需要另一个进程来捕获将在 dispose 方法中处理的任何超时线程。

如果您需要更清楚的说明,请告诉我,希望这对您有所帮助...

关于c# - IEndpointBehavior 生命周期/记录服务调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38648031/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com