2013-03-12 9 views
3

MessageInspector와 웹 서비스 간의 정보 공유에 관한 질문이 있습니다.MessageInspector와 웹 서비스 간의 공유 정보

필자는 AfterReceiveRequest와 BeforeSendReply를 "바인딩"하는 데 사용하는 식별자 (Guid)를 가지고 있습니다. 그것은 잘 작동합니다. 그러나이 식별자를 웹 서비스에서 사용되는 메서드에서도 사용할 수 있기를 바랍니다. 이것은 매우 유용합니다. 로그에서 문제를 추적합니다.

다음은 아이디어를 설명하기위한 작은 데모 예입니다. 내 문제는 메서드 AfterReceiveRequest에서 반환 개체에 액세스 할 수있는 솔루션을 찾을 것입니다. "MagicStuff"라인에.

namespace Demo.MessageInspector 
{ 
    public class DemoMessageInspector : IDispatchMessageInspector 
    { 
     public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
     { 
      Guid activityId = Guid.NewGuid(); 
      MyLog.Message("AfterReceiveRequest", activityId); 
      return activityId; 
     } 

     public void BeforeSendReply(ref Message reply, object correlationState) 
     { 
      Guid activityId = (Guid)correlationState; 
      MyLog.Message("BeforeSendReply", activityId); 
     } 
    } 
} 

namespace Demo.WebServices 
{ 
    [ServiceBehavior] 
    [MessageInterceptionServiceBehaviour] 
    public class MyWebService : IMyWebService 
    { 
     public void MyWebServiceMethod() 
     { 
      Guid activityId = (Guid)MagicStuff; // <-- correlationState from AfterReceiveRequest 

      bool success = DoSomthing(); 

      if (!success) 
       MyLog.Message("Error happened in MyWebServiceMethod", activityId); 
     } 
    } 
} 

나는 어떤 종류의 도움이나 힌트를 주셔서 감사합니다.

+0

[IDispatchMessageInspector Interface] (http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageinspector.aspx) 항목을 읽었습니까? –

+0

예 귀하가 참조한 설명을 읽었습니다 - 불행히도 제 문제에 대한 해결책을 찾지 못했습니다. 그러나 이것은 나에게 새로운 영역이며이 기능의 일부를 오해하지는 않을 것입니다. –

답변

5

OperationContext.IncomingMessageProperties Property을 사용할 수 있습니다. 여기에 시나리오의 사용이다 :

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Description; 
using System.ServiceModel.Dispatcher; 
using Demo.MessageInspector; 
using Demo.Utilities; 

namespace Demo.WebServices 
{ 
    public class MyWebService : IMyWebService, IServiceBehavior 
    { 
     public void MyWebServiceMethod() 
     { 
      // get the activityId from the incoming message properties 
      var activityIdProperty = OperationContext.Current.IncomingMessageProperties 
       .FirstOrDefault(property => property.Key == Properties.ActivityId.ToString()); 

      // create an empty Guid 
      Guid activityId = new Guid(); 
      if (activityIdProperty.Value != null) 
      { 
       // replace the empty Guid with the activityId 
       activityId = (Guid)activityIdProperty.Value; 
      } 
      bool success = DoSomething(); 
      if (!success) 
       MyLog.Message("Error happened in MyWebServiceMethod", activityId); 
     } 

     private bool DoSomething() 
     { 
      // TODO: implement 
      return false; 
     } 

     public void AddBindingParameters(
      ServiceDescription serviceDescription, 
      ServiceHostBase serviceHostBase, 
      System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, 
      BindingParameterCollection bindingParameters 
     ) 
     { 
      return; 
     } 

     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
      ServiceHostBase serviceHostBase) 
     { 
      foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers) 
      { 
       foreach (EndpointDispatcher epDisp in chDisp.Endpoints) 
       { 
        var messageInspector = new DemoMessageInspector(); 
        epDisp.DispatchRuntime.MessageInspectors.Add(messageInspector); 
       } 
      } 
     } 

     public void Validate(ServiceDescription serviceDescription, 
      ServiceHostBase serviceHostBase) 
     { 
      // TODO: implement validation 
      //throw new NotImplementedException(); 
     } 
    } 
} 

namespace Demo.MessageInspector 
{ 
    public class DemoMessageInspector : IDispatchMessageInspector 
    { 
     public object AfterReceiveRequest(ref Message request, 
      IClientChannel channel, InstanceContext instanceContext) 
     { 
      Guid activityId = Guid.NewGuid(); 

      // add the activityId to the incoming message properties 
      OperationContext.Current.IncomingMessageProperties 
       .Add(Properties.ActivityId.ToString(), activityId); 

      MyLog.Message("AfterReceiveRequest", activityId); 
      return activityId; 
     } 

     public void BeforeSendReply(ref Message reply, object correlationState) 
     { 
      Guid activityId = (Guid)correlationState; 
      MyLog.Message("BeforeSendReply", activityId); 
     } 
    } 
} 

namespace Demo.Utilities 
{ 
    public enum Properties 
    { 
     ActivityId 
    } 

    public class MyLog 
    { 
     internal static void Message(string p, Guid guid) 
     { 
      File.AppendAllText(@"C:\Temp\log.txt", 
       String.Format("{0} {1} {2}\r\n", DateTime.Now, p, guid)); 
     } 
    } 
} 

[업데이트]

또는, 당신은 CorrelationManager.ActivityId Property을 사용할 수 있습니다. Demo.Utilities.Helper 클래스를 추가, 그리고

<system.diagnostics> 
    <sources> 
    <source name="System.ServiceModel" propagateActivity="true"> 
     <listeners> 
     <add name="ignored" type="System.Diagnostics.DefaultTraceListener" /> 
     </listeners> 
    </source> 
    </sources> 
</system.diagnostics> 

다음과 같은 방법을 : 이렇게하려면 먼저 설정 파일 ( 클라이언트와 서버)에 다음을 추가

namespace Demo.Utilities 
{ 
    internal class Helper 
    { 
     internal static Guid GetCorrelationId() 
     { 
      var headerPosition = OperationContext.Current.IncomingMessageHeaders.FindHeader("ActivityId", 
       "http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics"); 
      if (headerPosition > -1) 
      { 
       var activityIdHeader = OperationContext.Current.IncomingMessageHeaders 
        .GetReaderAtHeader(headerPosition); 
       var activityIdAttribute = activityIdHeader.GetAttribute("CorrelationId"); 
       return Guid.Parse(activityIdAttribute); 
      } 
      else 
      { 
       return Guid.Empty; 
      } 
     } 
    } 
} 

는 이제 사용할 수 있습니다 DemoMessageInspector이 같은 방법 :

public object AfterReceiveRequest(ref Message request, 
    IClientChannel channel, InstanceContext instanceContext) 
{ 
    var correlationId = Helper.GetCorrelationId(); 
    MyLog.Message("AfterReceiveRequest\tCorrelationId", correlationId); 
    // ... 
} 

및 서비스의 방법이 같은 :

public void MyWebServiceMethod() 
{ 
    var correlationId = Helper.GetCorrelationId(); 
    MyLog.Message("MyWebServiceMethod\tCorrelationId", correlationId); 

    // ... 
} 
+0

알렉스. 고마워. 귀하의 제안은 매우 흥미롭게 보입니다. 나는 그것을 시도하고 가능한 빨리 결과와 함께 돌아올 것입니다. –