WCF代理客户端花时间为它创建任何缓存或单例解决方案

时间:2011-06-17 13:57:26

标签: wcf wcf-client

我们拥有多个wcf服务,并使用TCP绑定进行调用。在代码的不同位置有很多调用相同的wcf服务。

AdminServiceClient client = FactoryS.AdminServiceClient(); //需要很长时间。和

client.GetSomeThing(参数1); client.Close();

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

THX

2 个答案:

答案 0 :(得分:8)

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

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

创建代理时,您需要在内部频道

上订阅Faulted事件
proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyFaulted);

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

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

Edit2:保持通道打开和每次关闭之间唯一真正的负载差异是保持活动数据包被发送到服务并且经常被确认(这是您的通道故障事件的背后)。有100个用户,我不认为这将是一个问题。

另一个选项是将代理创建放在一个使用块中,它将在块的末尾关闭/处理(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;
            }
        }
    }
}

我希望有帮助:)

答案 1 :(得分:2)

根据我的经验,在每次通话的基础上创建/关闭频道会增加很少的开销。看看this Stackoverflow question。这本身不是单身人士问题,而是与您的问题有关。通常,您不希望在完成通道后将其保持打开状态。

如果您尚未使用reusable ChannelFactory implementation我会鼓励您使用{{3}},看看您是否仍有性能问题。