2011-06-01 123 views
3

我有這個奇怪的問題,當我的客戶端將從我的WCF服務調用方法時掛起。現在真正奇怪的是,當客戶端是控制檯應用程序時,不會發生這種情況。它發生在客戶端是WinForm或WPF應用程序時。從服務調用方法WCF客戶端凍結

我創建了一個WCF客戶端可以使用連接到服務的客戶端庫,在這裏看到:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ServiceModel; //needed for WCF communication 

namespace DCC_Client 
{ 
    public class DCCClient 
    { 
     private DuplexChannelFactory<ServiceReference1.IDCCService> dualFactory; 

     public ServiceReference1.IDCCService Proxy; 

     public DCCClient() 
     { 
      //Setup the duplex channel to the service... 
      NetNamedPipeBinding binding = new NetNamedPipeBinding(); 
      dualFactory = new DuplexChannelFactory<ServiceReference1.IDCCService>(new Callbacks(), binding, new EndpointAddress("net.pipe://localhost/DCCService")); 
     } 

     public void Open() 
     { 
      Proxy = dualFactory.CreateChannel(); 
     } 

     public void Close() 
     { 
      dualFactory.Close(); 
     } 
    } 

    public class Callbacks : ServiceReference1.IDCCServiceCallback 
    { 
     void ServiceReference1.IDCCServiceCallback.OnCallback(string id, string message, Guid key) 
     { 
      Console.WriteLine(string.Format("{0}: {1}", id, message)); 
     } 
    } 
} 

下面是工作 WCF控制檯客戶端代碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using DCC_Client; 

namespace Client_Console_Test 
{ 
    class Program 
    { 
     private static DCCClient DCCClient; 

     static void Main(string[] args) 
     { 
      try 
      { 
       DCCClient = new DCCClient(); 

       DCCClient.Open(); 

       DCCClient.Proxy.DCCInitialize(); //returns fine from here 

       Console.ReadLine(); 
       DCCClient.Proxy.DCCUninitialize(); 

       DCCClient.Close(); 
      } 
      catch (Exception e) 
      { 
       throw; 
      } 
     } 
    } 
} 

這裏是WPF客戶端的代碼凍結(看評論)

using System; //etc 

using DCC_Client; //Used for connection to DCC Service 

namespace Client_WPF_Test 
{ 
    public partial class Main : Window 
    { 
     private static DCCClient DCCClient; 

     public Main() 
     { 
      InitializeComponent(); 

      DCCClient = new DCCClient(); 

      DCCClient.Open(); 
     } 

     private void Connect_btn_event() { 

      try 
      { 
       DCCClient.Proxy.DCCInitialize(); //**never returns from this** 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.Message); 
      } 
     } 

我進入了代碼DCCClient.Proxy.DCCInitialize();,服務成功執行了這些命令,但是由於某些原因,客戶端卡在這裏並且不會繼續執行。客戶端不會例外,並且堆棧跟蹤顯示[外部代碼]。

這就是說,控制檯客戶端運行完美。我想我在這裏錯過了一些簡單的東西。我感謝您提供的任何幫助。

回答

13

如果您的服務直接從DCCInitialize回撥客戶端,並且操作和回調操作都未標記爲單向,則您的應用程序將會死鎖。試着用這個屬性標記您的回調實現:

[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)] 

的這種相反,你也可以嘗試用

[OperationContract(IsOneWay=true)] 

,以紀念這兩個合約的操作,但兩個操作必須返回void

在過去的如果這些都不能幫助您標記回調執行:

[CallbackBehavior(UseSynchronizationContext=false)] 

但在這種情況下,您的回調操作將在另一個線程中運行,並且將無法直接使用UI控件進行操作。

編輯:在UI線程託管時

WCF的行爲不同。在這種情況下,所有的請求都會在標準的windows消息循環中按順序處理,所以如果你調用服務,你阻塞了你當前的線程,但是服務調用了你的客戶端,它等待處理消息,但是它不能,因爲線程被阻塞初始調用=死鎖直到初始請求超時。通過使用最後提到的行爲,你會說WCF不加入Windows消息循環,而是像平常一樣在單獨的線程中處理消息。除此之外,沒有任何安全問題,除了不能從其他線程中運行的方法訪問UI控件 - WinForms和WPF都有辦法從其他線程傳遞命令。

+0

感謝拉迪斯拉夫您的快速回復。我的回撥在我的合同中已經有'[OperationContract(IsOneWay = true)]'。我嘗試在我的Callback實現中添加'[CallbackBehavior(ConcurrencyMode = ConcurrencyModel.Reentrant)]'並且客戶端仍然會凍結。然後我使用了'[CallbackBehavior(UseSynchronizationContext = false)]',它工作!是否有任何安全問題,我應該知道,因爲它是在一個不同的線程? – 2011-06-01 19:31:41

+0

我在描述中添加了我的答案。 – 2011-06-01 19:38:44

+0

+1。在嘗試了其他一些事情之後,'[CallbackBehavior(UseSynchronizationContext = false)]'也是我的問題的解決方案。 – 2015-05-21 09:41:33