2011-06-17 119 views
1

我想弄清楚爲什麼當你有多個回叫客戶端連接時使用着名的發佈 - 訂閱模式,當一個故障或當一個斷開連接時沒有取消訂閱所有客戶端狀態設置爲關閉,然後發生故障。所有WCF回調客戶端出現故障時發生故障

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallback))] 
    public interface IPubSubService 
    { 
     [OperationContract(IsOneWay = false, IsInitiating = true)] 
     void Subscribe(); 

     [OperationContract(IsOneWay = false, IsInitiating = true)] 
     void UnSubscribe(); 

     [OperationContract(IsOneWay = false)] 
     void BroadcastMessage(string message); 
    } 


    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] 
    public class PubSubService : IPubSubService 
    { 
     private ICallback _callbackClient; 
     public static event Action<string> _action; 

     public void Subscribe() 
     { 
     _callbackClient = OperationContext.Current.GetCallbackChannel<ICallback>(); 
     _action += ActionInvoked; 
     } 

     public void UnSubscribe() 
     { 
     _action -= ActionInvoked; 
     } 

     public void BroadcastMessage(string message) 
     { 
     _action.Invoke(message); 
     } 

     public void ActionInvoked(string message) 
     { 
     _callbackClient.SendMessage(message); 
     } 
    } 

    public interface ICallback 
    { 
     [OperationContract(IsOneWay = true)] 
     void SendMessage(string message); 
    } 


// The Publisher that doesn't subscribe only sends the message 
[CallbackBehaviorAttribute(UseSynchronizationContext = false)] 
    public partial class Form1 : Form, ICallback 
    { 
     public Form1() 
     { 
     InitializeComponent(); 
     } 

     private ServiceClient _proxy; 

     private void button1_Click(object sender, EventArgs e) 
     { 
     try 
     { 
      _proxy = new ServiceClient(new InstanceContext(this)); 
      _proxy.BroadcastMessage(textBox1.Text); 
     } 
     catch (Exception exception) 
     { 
      Console.WriteLine(exception); 
     } 
     } 


     public void SendMessage(string message) 
     { 

     } 
    } 

    public static class ControlExtensions 
    { 
     public static void Invoke(this Control Control, Action Action) 
     { 
     Control.Invoke(Action); 
     } 
    } 

    public class ServiceClient : DuplexClientBase<IPubSubService>, IPubSubService 
    { 
     public ServiceClient(InstanceContext callbackInstance) 
     : base(callbackInstance) 
     { } 

     public void Subscribe() 
     { 
     Channel.Subscribe(); 
     } 

     public void UnSubscribe() 
     { 
     Channel.UnSubscribe(); 
     } 

     public void BroadcastMessage(string message) 
     { 
     Channel.BroadcastMessage(message); 
     } 
    } 

// The Subscriber 
[CallbackBehaviorAttribute(UseSynchronizationContext = false)] 
    public partial class Form1 : Form, ICallback 
    { 
     public Form1() 
     { 
     InitializeComponent(); 
     } 

     private ServiceClient _proxy; 

     private void button1_Click(object sender, EventArgs e) 
     { 
     _proxy = new ServiceClient(new InstanceContext(this)); 
     _proxy.Subscribe(); 
     this.Invoke(() => textBox1.AppendText("Subscribed...")); 

     } 

     public void SendMessage(string message) 
     { 
     this.Invoke(() => textBox1.AppendText(message + "\r\n")); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
     if (_proxy != null && _proxy.State == CommunicationState.Opened) 
     { 
      _proxy.UnSubscribe(); 
     } 
     } 

     private void button3_Click(object sender, EventArgs e) 
     { 
     Thread.Sleep(new TimeSpan(0, 1, 0)); 
     } 
    } 

    public static class ControlExtensions 
    { 
     public static void Invoke(this Control Control, Action Action) 
     { 
     Control.Invoke(Action); 
     } 
    } 

    public class ServiceClient : DuplexClientBase<IPubSubService>, IPubSubService 
    { 
     public ServiceClient(InstanceContext callbackInstance) : base(callbackInstance) 
     { } 

     public void Subscribe() 
     { 
     Channel.Subscribe(); 
     } 

     public void UnSubscribe() 
     { 
     Channel.UnSubscribe(); 
     } 

     public void BroadcastMessage(string message) 
     { 
     Channel.BroadcastMessage(message); 
     } 
    } 


// config for both clients publisher and subscriber 

<configuration> 
    <system.windows.forms jitDebugging="true" /> 
    <system.serviceModel> 
    <bindings> 
     <netTcpBinding> 
     <binding name="netTCPBinding"> 
      <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="true"/> 
      <security mode="None"> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <client> 
     <endpoint 
     address="net.tcp://localhost:8008/PubSubService" 
     binding="netTcpBinding" 
     bindingConfiguration="netTCPBinding" 
     contract="ServiceLibrary.IPubSubService" 
     name="netTCPBinding"> 
     <identity> 
      <dns value="localhost"/> 
     </identity> 
     </endpoint> 
    </client> 
    </system.serviceModel> 
    <startup> 
    </startup> 
</configuration> 

// config for Service 

<?xml version="1.0"?> 
<configuration> 
    <system.serviceModel> 
    <services> 
     <service name="ServiceLibrary.PubSubService"> 
     <endpoint address="net.tcp://localhost:8008/PubSubService" 
        binding="netTcpBinding" 
        bindingConfiguration="netTCPBinding" 
        contract="ServiceLibrary.IPubSubService"/> 
     </service> 
    </services> 
    <bindings> 
     <netTcpBinding> 
     <binding name="netTCPBinding" closeTimeout="00:00:10" openTimeout="00:00:10" receiveTimeout="00:00:10" sendTimeout="00:00:10" transactionFlow="false" transferMode="Buffered" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="1000" maxReceivedMessageSize="65536"> 
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> 
      <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="true"/> 
      <security mode="None"> 
      </security> 
     </binding> 
     </netTcpBinding>  
    </bindings> 
    </system.serviceModel> 
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> 

回答

2

是不是簡單地斷開客戶端的情況下,導致事件提高拋出一個異常處理其調用列表的時候,因此,所有剩餘的客戶不要;噸被調用 - 你可以處理調用列表中手動東西這樣

 List<Action<string>> targets = _action.GetInvocationList().Cast<Action<string>>().ToList(); 

     foreach(var target in targets) 
     { 
      try 
      { 
       target(message); 
      } 
      catch(CommunicationException) 
      { 
       _action -= target; 
      } 
     } 

編輯(後看代碼)

您正在使用NetTcpBinding的這本質上是sessionful。該會話將在以下兩種情況中的一種情況下被拆除(斷開連接) - 當客戶端關閉其代理服務器或在請求之間的服務receiveTimeout超出時,關閉其代理服務器或

在您的PubSubService主機中,接收超時(影響訂閱者會話)設置爲5秒,與sendTimeout相同(這會影響您在廣播時確定訂閱服務器已停用之前等待的時間) 。因此,當你意識到用戶已經死亡,所有其他用戶已經超時他們的會話

在PubSubService主機中增加您的receiveTimeout達到您希望訂閱有效的時間並且它可以正常工作

+0

仍然是相同的結果,如果一個故障或關閉,他們都失去聯繫。 –

+0

好的,我們能否獲得關於您的設置的更多信息?你使用什麼綁定?客戶端代碼是什麼樣的?你如何主辦這項服務? –

+0

當然,我會編輯我原來的問題,並添加其餘的代碼和app.config設置。 –