6

我在网上找到了对我的问题的混合答案。详细说明这个问题:

  1. 我应该为每个异步调用实例化一次服务客户端代理,还是每个 Silverlight 应用程序一次?
  2. 我是否应该显式关闭服务客户端代理(就像在我的 ASP.NET MVC 应用程序中同步调用 WCF 服务一样)?

我发现很多博主和论坛海报相互矛盾。谁能指出任何明确的来源或证据来一劳永逸地回答这个问题?

4

3 回答 3

3

自 V2 以来,我一直在使用 Silverlight 和 WCF(现在使用 V4),这就是我发现的。一般来说,打开一个客户端并使用该客户端进行所有通信非常有效。如果你不使用 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);
            }
        }
    }

当然,烦人的部分是,如果您只有一个连接,您需要捕捉该连接何时意外关闭并尝试重新打开它。然后你需要重新初始化你的不同类注册处理的所有回调。这并不是真的那么困难,但确保它正确完成是很烦人的。当然,即使不是不可能,也很难对该部分进行自动化测试。. .

于 2009-12-19T23:31:46.910 回答
0

WCF have configuration settings that tells it how long it should wait for a call to return, my thinking is that when it does not complete in the allowed time the AsyncClose will close it. Therefore call client.AsyncClose().

于 2010-02-15T04:14:25.987 回答
0

您应该在每次通话时打开您的客户端并在之后立即关闭它。如果您对使用 IE 浏览到 SVC 文件有疑问,请查看那里的示例。

于 2009-11-11T14:42:50.190 回答