加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – IEndpointBehavior生命周期/日志服务调用

发布时间:2020-12-15 21:01:21 所属栏目:百科 来源:网络整理
导读:我正在尝试记录所有转发到服务引用的出站请求,包括完整的请求和响应正文.我以为我有一个使用behaviorExtensions的解决方案,但是在部署之后,很明显扩展是在多个请求之间共享的. 这是我目前的代码: public class LoggingBehaviorExtender : BehaviorExtension
我正在尝试记录所有转发到服务引用的出站请求,包括完整的请求和响应正文.我以为我有一个使用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的方法,所以我没有任何东西可以将异常日志绑定到服务请求日志.

解决方法

有几种方法可以解决这个问题.

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方法中处理的任何超时线程.

如果您需要更清晰,请告诉我,希望这有助于您……

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读