我遇到了一個調用客戶端回調方法的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()。
如果observingMarkets列表中只有一個項目,那麼只有一個調用服務的NotifyOnMarket()方法,並且一切工作正常。
但是,如果observedmarkets包含多個項目,那麼NotifyOnMarket()會以高頻率向服務器多次調用。
服務器上NotifyOnMarket()的實現調用一個方法,該方法又會調用回調方法SendMarketData(我評論過這個事實)。
在痕跡中,我可以看到serviceProxy.NotifyOnMarket(item);不會在第二個項目上返回,則會發生超時。
在服務器端,正確處理對NotifyOnMarket()的多重調用,並退出該方法。但如上所述,布爾結果不會顯示在客戶端(超時)。我們可以看到在服務器端調用了回調(這是單向的,所以沒有迴應會被返回),但是在客戶端沒有反應,因爲沒有調用回調實現。
我的結論是發生了某種類型的死鎖,這可能是由於客戶端實例鎖定自身,所以服務器無法調用回調方法。
將實例上下文類與也正在執行服務調用的類分開會更好嗎?如果是這樣,爲什麼?
謝謝你的建議,
克林斯曼
Thx爲鏈接。正如你可以看到我的回調實現,我將ConcurrencyMode設置爲多個(我也試過Reentrant)。這應該允許多線程客戶端上的多個調用。 ConcurrencyMode應該是告訴WCF我會爲自己做同步的唯一語句。但是,這並不能完成這項工作,因爲您可以在我的答案的博客文章鏈接中看到。當ConcurrencyMode = ConcurrencyMode.Multiple應該足夠時,使用ThreadPool是不合邏輯的解決方案。 – Juergen
我有一個類似的問題,它只有當我在服務實現類上添加[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]時才起作用,當我將它放在回調類上時它不起作用。 – Jonathan
那麼解決方案是什麼?我知道這是幾年前,但它仍然是其他人有價值的信息。我原以爲你的代碼會起作用,而將其改爲「重入」並不能解決問題。我很想複製你的測試,看看它是不是現在已修復的'11版本中的錯誤。 –