2016-07-28 1 views
4

전체 요청 및 응답 본문을 포함하여 서비스 참조로 이동하는 모든 아웃 바운드 요청을 기록하려고합니다. 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 
} 

... LoggingRequestExtender에 디버그 로깅을 추가

var lre = client.Endpoint.Behaviors.OfType<LoggingRequestExtender>().FirstOrDefault(); 
var req = lre?.Request; 
var resp = lre?.Response; 

, 나는 그것을 발견 여러 요청에 대해 한 번만 인스턴스화되었습니다.

이 동작 클래스가 각 스레드에 대해 새로 인스턴스화되었는지 확인하는 방법이 있습니까? 아니면 서비스 호출을 할 때 전체 요청/응답 본문을 얻는 더 좋은 방법이 있습니까?

편집/부분적인 대답 :

내가 GUID를 사용하여 요청 및 응답을 연결할 수 correlationState으로 내가 BeforeSendRequest에 의해 반환되는 값이 AfterReceiveReply로 전달되는 것을 발견했다이 작성 가입일 :

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 외부 GUID를 액세스하는 방법을 볼 수 없습니다/AfterReceiveReply 그래서 서비스 요청 로그에 예외 로그를 ​​묶는 게 없다 .

답변

0

여기에는 여러 가지 방법이 있습니다.

1 전화 통화를 별도로 기록해야하는 상황에서 그런 상황 일 필요는 없습니다. WCF 서비스가로드 균형이 조정되지 않은 서버에 있으면 Guid를 키로 사용하여 MemoryCache에 요청을 추가하십시오. 요청이 들어 오면 요청을 풀고 한 번 로그인하십시오. 시간 초과 된 호출을 캡쳐하려면 매 x 분마다 MemoryCache를 검사하여 스레드 안전성을 보장하는 적절한 잠금 장치를 사용하여 로그하는 프로세스를 스레드에서 실행할 수 있습니다.

WCF 서비스가로드 균형 조정 된 환경에 있으면 위와 동일하지만 no sql 형식 데이터 저장소에 저장하십시오.

2 변경 범위에서 발신 통화를하는 코드가 있습니까? 그렇다면 비헤이비어 확장 기능을 만들지 않고 맞춤형 메시지 로거를 대신 만들 수 있습니다. 이 같은 좋은 코드를 작성할 수는 IDisposable 구현하는 클래스를 사용하여 ..

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

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

이 것은 다음 어떤이 처분 방법으로 처리됩니다 스레드 시간 초과 캡처하는 다른 프로세스가 필요하지 않습니다.

당신이 더 명확하게 알고 싶다면, 잘하면이 도움이 ...