2009-11-10 57 views
6

我在網上找到了我的問題的混合答案。詳細說明這個問題:什麼是Silverlight 3中WCF服務客戶端代理的正確生命週期?

  1. 我應該在每個異步調用中實例化一次服務客戶端代理,還是每個Silverlight應用程序實例化一次?
  2. 我應該顯式關閉服務客戶端代理(就像我在ASP.NET MVC應用程序中同步調用WCF服務一樣)?

我發現很多博主和論壇海報互相矛盾。任何人都可以指出任何明確的來源或證據來回答這個問題嗎?

+0

答案可能取決於您的服務。創建代理非常昂貴,但跟蹤單個代理並管理任何錯誤可能很困難。 – Bryant 2009-11-10 23:37:56

回答

0

您應該打開您的客戶端每個電話並立即關閉它。如果您懷疑瀏覽使用IE瀏覽器的SVC文件,並看看他們在那裏的例子。

+0

儘管在Silverlight中使用的異步WCF調用的世界中,「緊隨其後」是什麼意思?在我開始異步調用之後關閉它,或者在完成時關閉它?如果是後者,它會提出如果從未完成會發生什麼的問題。 – Trinition 2009-11-11 15:20:08

3

我一直使用Silverlight與WCF V2以來(現在使用V4),這裏是我發現的。一般來說,打開一個客戶端並使用該客戶端進行所有通信非常有效。如果您沒有使用DuplexHttBinding,那麼也可以正好相反,每次打開一個新連接,然後在完成時關閉它。由於微軟在Silverlight中架構了WCF客戶端,因此在保持一個客戶端始終開放與每個請求創建一個新客戶端之間不會出現很多性能差異。 (但是,如果您正在創建一個新的客戶端,請確保您正在關閉它。)

現在,如果您使用的是DuplexHttBinding,即如果您想調用來自服務器的客戶端,這當然很重要,因爲您沒有關閉每個請求的客戶端。這只是常識。然而,沒有任何文檔告訴你,但我發現它是絕對關鍵的,就是如果你使用DuplexHttBinding,你應該只有一次打開客戶端的一個實例。否則,你將遇到各種令人討厭的超時問題,這些問題真的很難排除故障。如果你只有一個連接,你的生活將會變得更加簡單。

我在自己的代碼中執行此操作的方式是通過單個靜態DataConnectionManager類運行所有連接,如果在關閉第一個連接之前嘗試打開第二個連接,該類會引發Assert。從班上有幾個片段:

private static int clientsOpen; 
    public static int ClientsOpen 
    { 
     get 
     { 
      return clientsOpen; 
     } 
     set 
     { 
      clientsOpen = value; 
      Debug.Assert(clientsOpen <= 1, "Bad things seem to happen when there's more than one open client."); 
     } 
    } 

    public static RoomServiceClient GetRoomServiceClient() 
    { 
     ClientsCreated++; 
     ClientsOpen++; 
     Logger.LogDebugMessage("Clients created: {0}; Clients open: {1}", ClientsCreated, ClientsOpen); 
     return new RoomServiceClient(GetDuplexHttpBinding(), GetDuplexHttpEndpoint()); 
    } 

    public static void TryClientClose(RoomServiceClient client, bool waitForPendingCalls, Action<Exception> callback) 
    { 
     if (client != null && client.State != CommunicationState.Closed) 
     { 
      client.CloseCompleted += (sender, e) => 
      { 
       ClientsClosed++; 
       ClientsOpen--; 
       Logger.LogDebugMessage("Clients closed: {0}; Clients open: {1}", ClientsClosed, ClientsOpen); 
       if (e.Error != null) 
       { 
        Logger.LogDebugMessage(e.Error.Message); 
        client.Abort(); 
       } 
       closingIntentionally = false; 
       if (callback != null) 
       { 
        callback(e.Error); 
       } 
      }; 
      closingIntentionally = true; 
      if (waitForPendingCalls) 
      { 
       WaitForPendingCalls(() => client.CloseAsync()); 
      } 
      else 
      { 
       client.CloseAsync(); 
      } 
     } 
     else 
     { 
      if (callback != null) 
      { 
       callback(null); 
      } 
     } 
    } 

惱人的一部分,當然,如果你只有一個連接,你需要陷阱時無意中連接關閉,並嘗試重新打開它。然後你需要重新初始化你的不同類被註冊處理的所有回調。這並不是那麼困難,但是確保它的正確性是令人討厭的。當然,如果不是不可能的話,那部分的自動化測試也很困難。 。 。

0

WCF有配置設置,告訴它應該等待一個調用返回多長時間,我的想法是,當它沒有在允許的時間內完成時,AsyncClose會關閉它。因此調用client.AsyncClose()。

相關問題