【问题标题】:WCF Proxy Client taking time to create, any cache or singleton solution for itWCF 代理客户端需要时间来创建它的任何缓存或单例解决方案
【发布时间】:2011-09-17 05:32:22
【问题描述】:

我们有多个 wcf 服务,并使用 TCP 绑定进行调用。在代码的不同地方有很多对同一个 wcf 服务的调用。

AdminServiceClient client = FactoryS.AdminServiceClient();// it takes significant time. and 

client.GetSomeThing(param1);
client.Close();

我想缓存客户端或从单例中生成它。这样我可以节省一些时间,可以吗?

谢谢

【问题讨论】:

  • 什么样的应用程序正在使用代理 - 智能客户端或网络?

标签: wcf wcf-client


【解决方案1】:

是的,这是可能的。您可以使代理对象对整个应用程序可见,或者将其包装在单例类中以保持整洁(我的首选选项)。但是,如果您要为服务重用代理,则必须处理通道故障。

首先创建您的单例类/缓存/全局变量,其中包含您要重用的代理(或多个代理)的实例。

创建代理时,需要订阅内层频道的Faulted事件

proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyFaulted);

然后将一些重新连接代码放入 ProxyFaulted 事件处理程序中。如果服务中断或连接因空闲而超时,则会触发 Faulted 事件。只有在配置文件中的绑定上启用了可靠会话(如果未指定,则默认为在 netTcpBinding 上启用),错误事件才会触发。

编辑:如果您不想让代理通道一直保持打开状态,则必须在每次使用之前测试通道的状态,并在出现故障时重新创建代理。一旦通道出现故障,除了创建一个新通道之外别无选择。

Edit2:每次保持通道打开和关闭它之间的负载的唯一真正区别是一个keep-alive数据包被发送到服务并经常确认(这是您的通道故障事件背后的原因)。对于 100 个用户,我认为这不是问题。

另一种选择是将您的代理创建放在一个 using 块中,该块将在该块的末尾关闭/处置(即considered bad practice)。调用后关闭通道可能会导致您的应用程序挂起,因为服务尚未完成处理。事实上,即使你对服务的调用是异步的,或者方法的服务契约是单向的,通道关闭代码也会阻塞,直到服务完成。

这是一个简单的单例类,应该包含您需要的基本内容:

public static class SingletonProxy
{
    private CupidClientServiceClient proxyInstance = null;
    public CupidClientServiceClient ProxyInstance
    {
        get
        {
            if (proxyInstance == null)
            {
                AttemptToConnect();
            }
            return this.proxyInstance;
        }
    }

    private void ProxyChannelFaulted(object sender, EventArgs e)
    {
        bool connected = false;
        while (!connected)
        {
            // you may want to put timer code around this, or 
            // other code to limit the number of retrys if 
            // the connection keeps failing
            AttemptToConnect();
        }
    }

    public bool AttemptToConnect()
    {
        // this whole process needs to be thread safe
        lock (proxyInstance)
        {
            try
            {
                if (proxyInstance != null)
                {
                    // deregister the event handler from the old instance
                    proxyInstance.InnerChannel.Faulted -= new EventHandler(ProxyChannelFaulted);
                }

                //(re)create the instance
                proxyInstance = new CupidClientServiceClient();
                // always open the connection
                proxyInstance.Open();

                // add the event handler for the new instance
                // the client faulted is needed to be inserted here (after the open)
                // because we don't want the service instance to keep faulting (throwing faulted event)
                // as soon as the open function call.
                proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyChannelFaulted);

                return true;
            }
            catch (EndpointNotFoundException)
            {
                // do something here (log, show user message etc.)
                return false;
            }
            catch (TimeoutException)
            {
                // do something here (log, show user message etc.)
                return false;
            }
        }
    }
}

希望对你有帮助:)

【讨论】:

  • @Franchesca 如果您可以使用代码/参考进行更多解释。当频道一直打开与关闭频道时,有什么优点/缺点,因为有 100 个用户将访问该网站。谢谢
  • @Franchesca 感谢您的代码,我的另一个问题,所有 1000(对不起,我之前错误地写了 100),用户将使用单例对象,这些调用者可以同时在服务上调用不同的方法而没有任何性能受到打击或瓶颈,我担心。 1)我应该保持打开还是关闭。假设如果我在使用后关闭客户端,就像我的示例代码一样,然后单例再次调用 AttemptToConnect() 方法,然后使用多个客户端和单例没有区别。我是对的,如果不是,请给我一些解释。或任何其他策略,如池对象等。谢谢
  • 如果没有您当前架构的更多细节,很难给出一个好的答案。您是否有 1000 个用户访问 1000 个客户端应用程序实例,然后调用 WCF 服务,或者 1000 个用户都访问单个客户端实例(然后调用 WCF 服务)?
  • 如果不同的调用者需要同时调用不同的方法,那么他们每个人都需要有自己的服务代理对象实例。 WCF 服务可以配置为每次调用/每次会话运行实例,并且会根据您配置 InstanceContextMode 的方式自动为您管理池/负​​载。 See here for a general overview. 与其尝试编写代码来管理池,不如尝试使用可用的配置来实现您想要的。
  • @Franchesca 更多详细信息:我们在 perCall 模式下使用框架 4.0 WCF 服务。使用不活动超时 = 00:12 的 net.tcp,其他超时介于 0:2 到 0:5 之间。我们的代码使用带有静态生成代理的服务客户端调用服务。问题:我只是想减少 ServiceClient 创建时间,仅此而已。这就是为什么我想创建单例以便它可以只创建一次并分配给所有其他未来的调用者。现在你知道服务拱门了。如果我只对 Serviceclient 采用 Singleton 方法,请告诉我会有什么问题。
【解决方案2】:

根据我的经验,在每次调用的基础上创建/关闭频道几乎不会增加开销。看看this Stackoverflow question。这本身不是单例问题,而是与您的问题有关。通常情况下,您不想让频道在完成后保持打开状态。

如果您还没有使用reusable ChannelFactory implementation,我会鼓励您使用,看看您是否仍然遇到性能问题。

【讨论】:

    猜你喜欢
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 2012-10-24
    相关资源
    最近更新 更多