Silverlight 3中WCF服务客户端代理的正确生命周期是什么?

Silverlight 3中WCF服务客户端代理的正确生命周期是什么?,wcf,silverlight,wcf-client,wcf-proxy,Wcf,Silverlight,Wcf Client,Wcf Proxy,我在网上找到了各种各样的答案。要详细说明这个问题: 我应该为每个异步调用实例化一次服务客户端代理,还是为每个Silverlight应用实例化一次 我是否应该明确关闭服务客户端代理(就像我在同步调用WCF服务的ASP.NET MVC应用程序中所做的那样) 我发现很多博客和论坛海报相互矛盾。有人能指出任何确定的来源或证据来一劳永逸地回答这个问题吗?你应该在每次通话中打开你的客户,然后立即关闭它。如果您对使用IE浏览SVC文件有疑问,请查看其中的示例。我从V2开始就在WCF中使用Silverlight

我在网上找到了各种各样的答案。要详细说明这个问题:

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

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

    你应该在每次通话中打开你的客户,然后立即关闭它。如果您对使用IE浏览SVC文件有疑问,请查看其中的示例。

    我从V2开始就在WCF中使用Silverlight(现在使用V4),下面是我的发现。一般来说,打开一个客户机并将该客户机用于所有通信是非常有效的。如果您不使用DuplexHttBinding,也可以使用相反的方法,每次打开一个新连接,完成后再关闭。而且,由于Microsoft在Silverlight中构建WCF客户端的方式,您不会看到始终保持一个客户端打开与为每个请求创建一个新客户端之间的性能差异。(但如果您要为每个请求创建一个新客户端,请确保您也要关闭它。)

    现在,如果您正在使用DuplexHttBinding,也就是说,如果您想从服务器调用客户机上的方法,当然重要的是不要在每次请求时关闭客户机。这只是常识。但是,所有文档都没有告诉您,但我发现这一点非常关键,即如果您使用DuplexHttBinding,您应该一次只打开一个客户端实例。否则,您将遇到各种各样的令人讨厌的超时问题,这些问题将非常非常难以解决。如果你只有一个连接,你的生活会变得非常轻松

    我在自己的代码中实现这一点的方法是通过一个静态DataConnectionManager类运行所有连接,如果我在关闭第一个连接之前尝试打开第二个连接,该类将抛出断言。该类中的一些片段:

        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);
                }
            }
        }
    
    private static int clientsOpen;
    公共静态int ClientsOpen
    {
    得到
    {
    返回客户端;
    }
    设置
    {
    clientsOpen=值;
    Assert(clientsOpen
    {
    ClientsClosed++;
    客户索本--;
    LogDebugMessage(“客户端关闭:{0};客户端打开:{1}”,ClientsClosed,ClientsOpen);
    如果(例如错误!=null)
    {
    Logger.LogDebugMessage(例如错误消息);
    client.Abort();
    }
    关闭=错误;
    if(回调!=null)
    {
    回调(即错误);
    }
    };
    closing=true;
    如果(waitForPendingCalls)
    {
    WaitForPendingCalls(()=>client.CloseAsync());
    }
    其他的
    {
    client.CloseAsync();
    }
    }
    其他的
    {
    if(回调!=null)
    {
    回调(空);
    }
    }
    }
    

    当然,令人恼火的是,如果你只有一个连接,你需要在该连接无意中关闭时设置陷阱并尝试重新打开它。然后你需要重新初始化你的不同类注册要处理的所有回调。这其实并不是那么难,但确保正确操作是令人恼火的。当然,这一部分的自动测试即使不是不可能也很困难…

    WCF有配置设置,告诉它应该等待调用返回多长时间,我的想法是,当它没有在允许的时间内完成时,AsyncClose将关闭它。因此,调用client.AsyncClose().

    答案可能取决于您的服务。创建代理很昂贵,但跟踪单个代理并管理任何错误可能很困难。什么是“之后立即”呢但是,在Silverlight中使用的异步WCF调用中,是指在启动异步调用后关闭它,还是在完成时关闭它?如果是后者,则会引出一个问题:如果它从未完成,会发生什么。