2009-11-10 58 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()。

相关问题