2011-10-31 2 views
3

클라이언트에서 콜백 메서드를 호출하는 WCF 서비스에 문제가 발생했습니다. 먼저 서비스 :WCF 콜백 교착 상태

[ServiceContract(
SessionMode = SessionMode.Required, 
CallbackContract = typeof(IMarketObserver))] 
public interface IServer 
{ 
    ... 
    [OperationContract] 
    [FaultContractAttribute(typeof(WCFFaultDetail))] 
    bool NotifyOnMarket(EnumMarkets marketID); 
    ... 
} 

서비스 구현 :

[ServiceBehavior(
InstanceContextMode = InstanceContextMode.Single, 
ConcurrencyMode = ConcurrencyMode.Multiple, 
UseSynchronizationContext = false)] 
public sealed class Platform : IServer 
{ 
... 
public bool NotifyOnMarket(EnumMarkets marketID) 
{ 
    try 
    { 
     IMarketObserver callback = OperationContext.Current.GetCallbackChannel<IMarketObserver>(); 
     if (subscribers.Contains(callback) == false) 
     { 
      subscribers.Add(callback); 
     } 
    } 
    catch 
    { 
     return false; 
    } 
    //This call may cause a call to the callback method SendMarketData()!! 
    callSomeMethod(); 
    return exchangeProxy.IsMarketIDValid(); 
} 

콜백 계약 :

public interface IMarketObserver 
{ 
    [OperationContract(IsOneWay = true)] 
    void SendMarketData(MarketData marketData); 
} 

이 콜백의 클라이언트 구현은이 :

[CallbackBehavior(
    ConcurrencyMode = ConcurrencyMode.Multiple, 
    UseSynchronizationContext = false)] 
public class MarketBase : 
    IServerCallback 
{ 
    protected IService serviceProxy; 
    public void SendMarketData(MarketData marketData) 
    { 
     //Do something 
    } 
    private void NotifyOnMarkets() 
    { 
     foreach (EnumMarkets item in observedMarkets) 
     { 
      try 
      { 
       bool res = serviceProxy.NotifyOnMarket(item); 
      } 
      catch (Exception e) 
      { 
      ... 
      } 
     } 
    } 

문제가 발생합니다 때 c foreach 루프를 사용하여 NotifyOnMarkets()를 호출합니다.

obserasedMarkets 목록에 하나의 항목 만있는 경우 서비스의 NotifyOnMarket() 메소드에 대한 호출이 정확히 하나이므로 모든 것이 올바르게 작동합니다.

그러나 관찰 된 MarketSet에 둘 이상의 항목이 포함되어 있으면 NotifyOnMarket()이 서버에 빈번하게 자주 호출됩니다.

서버에서 NotifyOnMarket()을 구현하면 메서드를 호출하여 콜백 메서드 인 SendMarketData를 호출합니다 (이 사실을 알았습니다).

추적에서 볼 수있는 그 serviceProxy.NotifyOnMarket (item); 두 번째 항목으로 돌아 오지 않으면 시간 초과가 발생합니다.

서버 측에서는 NotifyOnMarket()에 대한 다중 호출이 올바르게 처리되고 메서드가 종료됩니다. 그러나 위에서 언급했듯이 부울 결과는 클라이언트에 표시되지 않습니다 (시간 초과).

또한 서버 측에서 콜백이 호출 됨 (단방향이므로 응답이 반환되지 않음)을 볼 수 있지만 클라이언트 측에서는 콜백 구현이 호출되지 않기 때문에 아무 일도 발생하지 않습니다.

필자의 결론은 일종의 교착 상태가 발생했으며 이는 클라이언트 인스턴스가 잠겨서 서버가 콜백 메소드를 호출 할 수 없기 때문일 수 있습니다.

서비스 호출을 수행하는 클래스에서 인스턴스 컨텍스트 클래스를 분리하는 것이 더 좋습니까? 그렇다면 왜? 조언을

감사합니다,

위르겐 질문에 대한

답변

4

: 그것은 다른 스레드에있을 필요가 왜?

는 WCF가 을 말한다 규칙을 적용하여 믹스에 더 많은 복잡성을 추가

는 "당신이 달리 말해 않는 한 나는 단지 내가 제어 객체에 한 번 에 하나 개의 스레드를 허용 할 것이다" WCF Duplex Messaging의 끝을보기 . 싱글 톤 서비스 으로 볼 수 있는데, 기본적으로 한 번에 하나의 호출 만 허용됩니다. 동일한 것은 콜백 구현 객체의 true이기 때문에 WCF는 클라이언트에서 한 번에 하나의 활성 스레드 인 만 허용합니다. 따라서 WCF가 아웃 바운드 호출을 수행하는 동안 개체로의 인바운드 호출을 허용하지 않습니다. 이로 인해 클라이언트의 아웃 바운드 호출이 진행 중일 때 서비스의 콜백을 전달할 수없는 교착 상태의 초기 문제가 발생합니다. 이 문제를 해결하기 위해 위의 규칙 중 부분을 사용합니다. 이 같은 [CallbackBehavior] 속성으로 콜백 구현 클래스를 주석하여이 작업을 수행 :

[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)] 
+0

링크의 Thx. 내 콜백 구현에서 볼 수 있듯이 ConcurrencyMode를 여러 개로 설정했습니다 (또한 Reentrant를 시도했습니다). 이렇게하면 여러 스레드가있는 클라이언트에서 여러 호출을 허용해야합니다. ConcurrencyMode는 WCF에게 자신을 위해 동기화를 수행 할 것임을 알리는 유일한 문이어야합니다. 그러나 이것은 내 대답의 블로그 게시물 링크에서 볼 수있는 것처럼 일을하지 않습니다. ConcurrencyMode = ConcurrencyMode.Multiple이면 충분합니다. ThreadPool을 사용하는 것은 논리적 솔루션이 아닙니다. – Juergen

+0

서비스 구현 클래스에서 [ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Reentrant)]를 추가했을 때만 비슷한 문제가 발생했습니다. 콜백 클래스에 넣을 때 작동하지 않습니다. – Jonathan

+0

그래서 해결책은 무엇입니까? 나는 이것이 수년 전 이었음을 안다. 그러나 그것은 여전히 ​​다른 사람들에게 가치있는 정보이다. 나는 당신의 코드가 작동 할 것이라고 생각했을 것이다. 그리고 그것을 "re-entrant"로 바꾸면 문제가 해결되지 않을 것이다. 나는 당신의 테스트를 복제하고 11 월에 버그가 있었는지 지금은 고쳐 졌는지에 유혹을 받는다. –

0

당신은 (복수 또는 재 참가자 모두 작업으로 설정하여 바로 그 일을하고 있지만 다시 참가자는 한 번에 한 스레드 씩 강제 수행하고 여러 스레드는 한 번에 여러 스레드가 서비스에 참여할 수있게합니다. 한 번에 여러 스레드가 서비스를 입력해야하지 않는 한 개인적으로 "재진입"으로 설정했습니다.

예제를 따라 내 컴퓨터에 테스트 케이스를 작성 했으므로 제대로 작동했습니다. 나는 당신의 IIS 구현 (11 년경)에 버그가 있다고 생각한다. 테스트는 불가능합니다.