我在网上找到了我的问题的混合答案.详细说明问题:
>我应该为每个异步调用实例化一次服务客户端代理,还是每个Silverlight应用实例一次?
>我应该显式关闭服务客户端代理(就像我在同时调用WCF服务的ASP.NET MVC应用程序中那样)吗?
我发现很多博主和论坛海报相互矛盾.任何人都可以指出任何明确的消息来源或证据来一劳永逸地回答这个问题吗?
解决方法
自从V2(现在使用V4)以来,我一直在使用Silverlight和WCF,这就是我发现的.一般来说,它可以很好地打开一个客户端,只需使用一个客户端进行所有通信.如果您没有使用DuplexHttBinding,它也可以正常工作,每次打开一个新连接,然后在完成后关闭它.而且由于Microsoft在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); } } }
当然,烦人的部分是,如果你只有一个连接,你需要陷阱,当连接无意中关闭并尝试重新打开它.然后,您需要重新初始化您的不同类注册要处理的所有回调.这并不是那么困难,但要确保它做得对,这很烦人.当然,即使不是不可能,也很难对该部件进行自动化测试. . .