2013-05-01 1 views
1

이 단어를 올바르게 말하면 좋을 것입니다. 하나의 클라이언트가 서비스에 등록 할 때 사용하는 WCF 서비스 (이중 채널 통신)가 있습니다. 서비스의 등록 메소드는 값을 리턴합니다. 클라이언트 등록 알림을 보낼 콜백 메서드를 호출하려면 호출 된 서비스 등록 메서드의 메서드를 원합니다. (여기에는 내 이유가 있으며 여기에서 설명하면 문제가 혼동 될뿐입니다). 문제는 클라이언트의 구현 된 콜백이 올바르게 작동하기 위해 (주로 타사 응용 프로그램과의 통합으로 인해) 주 응용 프로그램 스레드에서 실행되어야한다는 것입니다. 서비스 등록 메소드 호출도이 동일한 스레드에서 발생하기 때문에 클라이언트가 서비스 등록 메소드에서 반환하는 스레드를 보유하고있어 콜백 메소드를 실행할 수 없으므로 클라이언트가 효과적으로 잠기므로 효과적으로 잠급니다. 방금 등록한 것 이외의 모든 컨텍스트에 대해 모든 콜백 메소드를 호출하도록 말하면 잘 작동합니다. 그러나 그것을 포함 시키라고 말하면 분명히 그 스레드는 이미 잠겨 있기 때문에 잠긴다. UseSynchronizationContext에 대한 콜백 속성 속성을 false로 설정할 수 있지만 콜백 메서드는 주 스레드와 별도의 스레드에서 호출되므로 나머지 프로그램은 작동하지 않습니다. 어떤 도움이라도 대단히 감사하겠습니다.WCF 현재 컨텍스트와 동일한 스레드에서 호출 된 경우 콜백 잠금

여기에 기본적으로 그 등록 방법입니다 (첫 번째 초안 ..)

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, 
        UseSynchronizationContext = false, 
        ConcurrencyMode = ConcurrencyMode.Multiple, 
        Namespace = "http://MyApp/Design/CADServiceTypeLibrary/2012/12")] 
    public class DTOTransactionService : IDTOTransactionService, IDisposable 
    { 
      //some more stuff 

public CADManager RegisterCADManager(int processID, bool subscribeToMessages) 
     { 

      List<CADManager> cadMgrs = this.CADManagers; 

      bool registered = false; 

      //Create new CADManager mapped to process id 
      CADManager regCADManager = new CADManager(processID); 

      //Add to CADManagers List and subscribe to messages 
      if (regCADManager.IsInitialized) 
      { 
       cadMgrs.Add(regCADManager); 
       this.CADManagers = cadMgrs; 

       //Subscribe to callbacks 
       if (subscribeToMessages) 
        SubscribeCallBack(regCADManager.ID); 

       registered = true; 
      } 

      //Send registration change notification 
      RegistrationState state; 
      if (registered) 
       state = RegistrationState.Registered; 
      else 
       state = RegistrationState.RegistrationException; 

      foreach (CallBackSubscriber subscriber in this.CallBackSubscribers) 
      { 
        subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state); 
      } 

      return regCADManager; 
     } 
} 

답변

1

내가 그것을 알아 냈있어 생각합니다. 서비스 메소드에 대한 호출이 반환 값을 기대하고 클라이언트 메소드와 동일한 스레드에서 콜백이 발생할 것이므로 반환 값을 예상하여 교착 상태가 발생할 수 있기 때문에 상황이 조금 더 깊어졌습니다. 조건. 그런 다음 다른 스레드를 사용하는 서비스에서 콜백 메소드를 호출하여 현재 스레드 조건을 해결하려고했습니다. 즉, 메소드가 아직 서비스 메소드의 반환 값을 제공하지 않은 현재 스레드 주변에서 작업하십시오. 그것은 효과가있다! 이것이 올바른 접근 이었습니까? 나는 여기에 위험 할 정도로 충분한 경험을 가지고 있기 때문에, 다른 사람의 경험에 의하면 이것을 이것을 처리하는 잘못된 방법으로 보여 준다면 나는 모두 귀가 다.

 Thread notifyThread = new Thread(delegate() 
     { 
      foreach (CallBackSubscriber subscriber in this.CallBackSubscribers) 
      { 
       subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state); 
      } 
     }); 


업데이트 :

예, 스레딩 및 교착 상태가 문제가 있었다, 그러나 나는 최근에 발견 된 더 적절한 수정에서 SynchronizationContext를 사용하는 것입니다. 사용하려면 SynchronizationContext 유형의 속성이나 필드를 만든 다음 SynchronizationContext.Current를 사용하여 캡처하려는 컨텍스트에서 필드/속성에 값을 할당합니다. 그런 다음 서비스에서 호출하는 콜백 메서드에서 Post() 메서드 (SendOrPostCallback 개체를 통해 대리자 제공)를 사용합니다. 간단한 예 :

private SynchronizationContext _appSyncContext = null; 

    private DTOCommunicationsService() 
    { 
     this.AppSyncContext = SynchronizationContext.Current; 

     //Sets up the service proxy, etc, etc 
     Open(); 
    } 

    // Callback method 
    public void ClientSubscriptionNotification(string clientID, SubscriptionState subscriptionState) 
    { 
     SendOrPostCallback callback = delegate(object state) 
     { 
      object[] inputArgs = (object[])state; 
      string argClientID = (string)inputArgs[0]; 
      SubscriptionState argSubState = (SubscriptionState)inputArgs[1]; 

      //Do stuff with arguments 

     }; 

     _appSyncContext.Post(callback, new object[] { clientID, subscriptionState }); 
    } 
관련 문제