7

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

शेखर
  • 17,412
  • 13
  • 61
  • 117
Techmaster
  • 1,032
  • 2
  • 12
  • 26

2 Answers2

8

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 :)

Franchesca
  • 1,453
  • 17
  • 32
  • @Franchesca if you can explain bit more with the code/reference. What are the advantages/dis, when channel is open all the time vs close channel, as 100 of users will be accessing the website. Thx – Techmaster Jun 17 '11 at 15:14
  • @Franchesca thanks for the code, my another question, all the 1000 (sorry earlier i mistakenly wrote 100), users will be using the singleton object, Can these callers call different method on service simultaneously without any performance hit or bottleneck, My worries. 1) Should i keep it open or close.Suppose if i close the client after use as in my sample code, then singleton again call AttemptToConnect() method, then using multiple client and Singleton don't make a difference. Am i right, if not please give me some explanation. or any other strategy like pooling objects etc. Thanks – Techmaster Jun 17 '11 at 17:30
  • It's hard to give a good answer without more details of your current architecture. Do you have 1000 users hitting 1000 instances of the client application that is then calling the WCF service, or 1000 users all accessing a single instance of the client (that is then calling the WCF service)? – Franchesca Jun 17 '11 at 21:54
  • If your different callers need to call different methods simultaniously, then they will each need to have their own instance of the service proxy object. WCF services can be configured to run instances per call / per session, and will automatically manage pooling / load for you depending on how you configure the InstanceContextMode. [See here for a general overview.](http://msdn.microsoft.com/en-us/library/ms554644.aspx) Rather than trying to write code to manage pooling, try and use the available configuration to achieve what you want. – Franchesca Jun 17 '11 at 21:55
  • @Franchesca More Details: We are using framework 4.0 WCF service in perCall Mode. using net.tcp with inactivity timeout=00:12, other timeout between 0:2 to 0:5. Our code calls the service using Service Client with statically generated Proxies. Question: I just want to reduce the ServiceClient creation tim,e thats all. Thats why i was wondering to create the singleton so that it can be created just once and be assigned to all other future callers. Now you know about arch of service. Tell me will there be any issues if i go by the Singleton approach for Serviceclient only. – Techmaster Jun 18 '11 at 10:59
  • Is there a big overhead when creating an instance of your WCF service? perCall mode means that you are creating a new instance of your service every single time you call the service from a proxy. This could be why things are a little slow. Try changing your service to perSession mode (so you are reusing the same service instance for multiple calls). – Franchesca Jun 18 '11 at 11:54
  • @EkoostikMartin What do you mean? Did you just copy paste code from the internet into your project and expect it to work? That's hardly a reason to give -1. If you need help then ask a question :) – Franchesca Jul 04 '13 at 13:55
  • @Franchesca - no I didn't copy/paste the code, but there are numerous errors (of different kinds), you should really mark it is pseudo-code. – EkoostikMartin Jul 05 '13 at 19:16
  • @EkoostikMartin This site is a platform for helping people, you should try to be more constructive in your comments if you want to help me and others improve their answers. Anything else is just pointless trolling ;) – Franchesca Jul 09 '13 at 13:47
  • Okay, here are some problems with the code I encountered. Static class with non-static methods (build error), Infinite loop in Fault event handler (design error), you shouldn't lock the whole try/catch block (performance), also by locking on proxyInstance, you are essentially locking on a public type (since it is exposed through a property), you should lock on a private static object variable instead (best practice to prevent deadlock/starvation). – EkoostikMartin Jul 09 '13 at 17:56
2

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.

Community
  • 1
  • 1
BrandonZeider
  • 8,014
  • 2
  • 23
  • 20