2013-03-01 33 views
0

以下是Duplex Service及其WebConfig文件。在服務中,發送客戶端通過TransmitUserData方法發送它的數據並且接收客戶端通過來自CallBackContract的PublishUserData接收數據。WCF- System.ServiceModel.Channels.ServiceChannel已被中止

現在的問題是,如果我第一次運行客戶端它的工作完美,但如果我重新運行客戶端,它會給出以下錯誤傳輸Project can be found here.Here is the Service Log File (.svclog)

的通信對象,System.ServiceModel.Channels.ServiceChannel, 不能用於通信,因爲它已被中止。

雙工服務合同

[ServiceContract(CallbackContract=typeof(IContactManagerCallBackService))] 
    public interface IContactManagerUserService 
    { 
     [OperationContract(IsOneWay = true)] 
     void SubscribeAsReceiver(); 

     [OperationContract(IsOneWay = true)] 
     void SubscribeAsTransmitter(); 

     [OperationContract] 
     void TransmitUserData(UserInfo info); 

    } 

    [ServiceContract] 
    public interface IContactManagerCallBackService 
    { 
     [OperationContract(IsOneWay = true)] 
     void PublishUserData(UserInfo info);   
    } 

    [DataContract] 
    public class UserInfo 
    { 
     [DataMember] 
     public bool PaidUser { get; set; } 

     [DataMember] 
     public string ProfileName{ get; set;} 

     [DataMember] 
     public string ComputerName { get; set; } 

     [DataMember] 
     public string IPAddress { get; set; } 

     [DataMember] 
     public string MACAddress { get; set; } 
    } 

服務實現

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] 
    public class ContactManagerUserService : IContactManagerUserService 
    { 
     SynchronizedCollection<IContactManagerCallBackService> receiverClients; 

     public ContactManagerUserService() 
     { 
      receiverClients = new SynchronizedCollection<IContactManagerCallBackService>(); 
     } 

     public void SubscribeAsReceiver() 
     { 
      IContactManagerCallBackService client = OperationContext.Current.GetCallbackChannel<IContactManagerCallBackService>(); 
      receiverClients.Add(client); 
     } 

     public void TransmitUserData(UserInfo info) 
     { 
      foreach (IContactManagerCallBackService receiverClient in receiverClients) 
      { 
       receiverClient.PublishUserData(info);      
      }     
     } 

的Web.config

<system.serviceModel> 
    <diagnostics> 
     <messageLogging logEntireMessage="true" logMalformedMessages="true" 
     logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" /> 
    </diagnostics> 
    <bindings> 
     <netTcpBinding> 
     <binding name="NewBinding0" maxConnections="1000" 
      portSharingEnabled="true"> 
      <security mode="None" /> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <services> 
     <service name="ContactManagerService.ContactManagerUserService"> 
     <endpoint address="mex" binding="netTcpBinding" bindingConfiguration="" 
      name="dataEndPoint" contract="ContactManagerService.IContactManagerUserService" /> 
     <endpoint binding="mexTcpBinding" bindingConfiguration="" name="mexHttp" 
      contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="net.tcp://localhost/ContactManagerUserService" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name=""> 
      <serviceMetadata httpGetEnabled="false" /> 
      <serviceDebug includeExceptionDetailInFaults="true" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> 
    </system.serviceModel> 

編輯:

的代碼完全運行首次。 實際上問題是由Transmitter創建的,我們從不訂閱或取消訂閱。 enter image description here

回答

3

第一個接收器退出後,其通道仍保存在服務器的receiverClients集合中,所以下次發生傳輸時,服務器將嘗試回撥到不存在的客戶端。您必須在集合結束時從集合中刪除接收者,可能需要取消訂閱合同操作。有很多方法可以實現這一點。這是一個例子。 (這些都是變化,唯一的 - 請讓我知道如果你想整個項目。)

在IContactManagerUserService.cs:

// receivers must identify themselves 
[OperationContract(IsOneWay = true)] 
void SubscribeAsReceiver(string receiverID); 

// new operation 
[OperationContract(IsOneWay = true)] 
void UnSubscribeAsReceiver(string receiverID); 

在ContactManagerUserService.cs

// replace synchronized collection with thread-safe dictionary 
using System.Collections.Concurrent; 

ConcurrentDictionary<string, IContactManagerCallBackService> receiverClients; 

public ContactManagerUserService() 
{ 
    receiverClients = new ConcurrentDictionary<string, IContactManagerCallBackService>(); 
} 

public void SubscribeAsReceiver(string receiverID) 
{ 
    IContactManagerCallBackService client = OperationContext.Current.GetCallbackChannel<IContactManagerCallBackService>(); 
    receiverClients.TryAdd(receiverID, client); 
} 

public void UnSubscribeAsReceiver(string receiverID) 
{ 
    IContactManagerCallBackService client; 
    receiverClients.TryRemove(receiverID, out client); 
} 

public void TransmitUserData(UserInfo info) 
{ 
    foreach (IContactManagerCallBackService receiverClient in receiverClients.Values) 
    { 
     receiverClient.PublishUserData(info);     
    }   
} 

在ReceiverClient 。程序。CS(不要忘記更新ServiceReferences因爲合同已經改變):

// one way to uniquely identify this receiver 
string rcvID = Guid.NewGuid().ToString(); 
// .... // 
receivingClient.SubscribeAsReceiver(rcvID); 
// .... // 

Console.ReadLine(); 

// Important - this line must be executed, or service will again throw error. 
// So when debugging, don't just close window, press enter to execute this line. 
// In more robust setting, this would probably go in finally{} block, or in Dispose() 

receivingClient.UnSubscribeAsReceiver(rcvID); 

調試提示您可能希望有一個版本的服務,你可以在本地運行,這樣你就可以進入它和調試它。另外,當您無法在本地運行服務時,我發現日誌消息到服務日誌非常有用。

您可以搜索WCF發佈者/訂戶以獲取更多信息。

+0

是的,如果你可以在'nirajdoshi1985 [at] gmail [dot] com' – Marshal 2013-05-17 12:27:34

+0

給我發送代碼,那就好了嗨Alex,謝謝你的代碼。它第一次運行完美,但是當我第二次運行時,變送器會導致問題(我們從不訂閱或取消訂閱)。請參閱編輯 – Marshal 2013-05-17 14:04:56

+0

user1467261:再向前一步,如果我關閉接收器窗口,發射器會引發上述異常中止。不知怎的,頻道正在中止。 – Marshal 2013-05-17 14:19:16

1

1)您可以使用IErrorHandle來捕獲此異常(可能有用)。在回調(序列化/(un)KnownType(s)問題)中通常會引發異常。

2)如果在服務器/服務端(在svclog中)看不到問題 - 通信中止的根本原因可能在客戶端上。 看看你在客戶端的回調實現。如果在回調方法(引發事件處理程序等)中拋出異常並且它被吞下(或者由於某種原因您錯過了它,可能是因爲它不會在UI線程或其他東西中拋出......調試器沒有通知您) - 它會(或可能)中止通信(客戶端代理將出現故障)。

+0

但如何捕捉客戶端異常? – Marshal 2013-05-13 04:44:49

+0

只是用try/catch內部的客戶端回調實現 – SalientBrain 2013-05-14 09:22:04