Ich versuche, alle ausgehenden Anfragen, die zu Service-Referenzen gehen, einschließlich der vollständigen Anfrage und Antwort Körper zu protokollieren. Ich dachte, ich hätte eine Lösung mit behaviorExtensions, aber nach der Bereitstellung wurde klar, dass die Erweiterung zwischen mehreren Anfragen geteilt wurde.IEndpointBehavior Lebenszyklus/Logging Serviceaufrufe
Hier ist meine aktuellen Code:
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
}
Dann, als ich den Punkt erreicht, zu protokollieren, ich das Verhalten extrahieren ...
var lre = client.Endpoint.Behaviors.OfType<LoggingRequestExtender>().FirstOrDefault();
var req = lre?.Request;
var resp = lre?.Response;
Debug-Protokollierung der LoggingRequestExtender Hinzufügen, fand ich es wurde nur einmal für mehrere Anfragen instanziiert.
Gibt es eine Möglichkeit, sicherzustellen, dass diese Verhaltensklasse für jeden Thread neu instanziiert wird? Oder gibt es eine bessere Möglichkeit, den vollständigen Anfrage-/Antworttext bei Serviceanrufen zu erhalten?
Bearbeiten/Partial Antwort:
Da dieses Schreiben ich, dass der Wert von BeforeSendRequest zurück entdeckt habe, ist in AfterReceiveReply vergangen als correlationState so kann ich die Anfrage und Antwort mit einem guid verbinden:
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());
}
Ich sehe zwei Fehler zu diesem Ansatz. Eine, die lebenswert ist, ist, dass dies eine Protokolleinfügung erfordert und dann aktualisieren, anstatt eine einzelne Einfügung.
Die zweite ist mehr ein Problem: Im Falle einer Ausnahme (z. B. Timeout), treffen wir nie AfterRecieveSupply, so dass das Protokoll nicht weiß, was passiert ist. Ich kann separat die Ausnahme log ...
try
{
response = client.SomeFunction(request);
}
catch (Exception ex)
{
AppLog.Error("Some function failed", ex);
}
... aber ich kann nicht einen Weg, den Zugriff auf die guid außerhalb von BeforeSendRequest/AfterReceiveReply so ich habe nichts zu binden das Ausnahmeprotokoll an den Dienstanforderungsprotokoll sehen .