Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF Proxy Client taking time to create, any cache or singleton solution for it

Tags:

wcf

wcf-client

we have more than dozon of wcf services and being called using TCP binding. There are a lots of calls to same wcf service at various places in code.

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

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

i want to cache the client or produce it from singleton. so that i can save some time, Is it possible?

Thx

like image 555
Techmaster Avatar asked Jun 17 '11 13:06

Techmaster


2 Answers

Yes, this is possible. You can make the proxy object visible to the entire application, or wrap it in a singleton class for neatness (my preferred option). However, if you are going to reuse a proxy for a service, you will have to handle channel faults.

First create your singleton class / cache / global variable that holds an instance of the proxy (or proxies) that you want to reuse.

When you create the proxy, you need to subscribe to the Faulted event on the inner channel

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

and then put some reconnect code inside the ProxyFaulted event handler. The Faulted event will fire if the service drops, or the connection times out because it was idle. The faulted event will only fire if you have reliableSession enabled on your binding in the config file (if unspecified this defaults to enabled on the netTcpBinding).

Edit: If you don't want to keep your proxy channel open all the time, you will have to test the state of the channel before every time you use it, and recreate the proxy if it is faulted. Once the channel has faulted there is no option but to create a new one.

Edit2: The only real difference in load between keeping the channel open and closing it every time is a keep-alive packet being sent to the service and acknowledged every so often (which is what is behind your channel fault event). With 100 users I don't think this will be a problem.

The other option is to put your proxy creation inside a using block where it will be closed / disposed at the end of the block (which is considered bad practice). Closing the channel after a call may result in your application hanging because the service is not yet finished processing. In fact, even if your call to the service was async or the service contract for the method was one-way, the channel close code will block until the service is finished.

Here is a simple singleton class that should have the bare bones of what you need:

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;
            }
        }
    }
}

I hope that helps :)

like image 171
Franchesca Avatar answered Oct 07 '22 04:10

Franchesca


In my experience, creating/closing the channel on a per call basis adds very little overhead. Take a look at this Stackoverflow question. It's not a Singleton question per se, but related to your issue. Typically you don't want to leave the channel open once you're finished with it.

I would encourage you to use a reusable ChannelFactory implementation if you're not already and see if you still are having performance problems.

like image 23
BrandonZeider Avatar answered Oct 07 '22 04:10

BrandonZeider