我試圖記錄所有出站請求轉到服務引用,包括完整的請求和響應正文。我以爲我有一個使用behaviorExtensions的解決方案,但是在部署之後,很明顯擴展是在多個請求之間共享的。IEndpointBehavior生命週期/日誌記錄服務調用
這裏是我當前的代碼:
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作爲correlationState這樣我就可以使用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);
}
...但我看不到的訪問的GUID BeforeSendRequest之外的方式/ AfterReceiveReply所以我沒有什麼異常日誌綁到服務請求日誌。