Dailycode.info

Short solution for short problems

Using a singleton class to cache the WCF services

I’ve written several articles on generic singleton and WCF. I think it’s very powerfull. After some implementations, the code gets better and better. Together with a collague I created a generic factory to instantiate services. Then I add them to a singleton class to cache them. This works great.

First time I got some trouble with it was because the server only allowed 20 instances of a service for a session. To avoid exceptions messing up the connections, I created a new channel for each call. But the channel is not closed in a good way because of the singleton class. Therefore I needed some good exception handling. For certain exceptions I reopen the service letting go of the previous connection and creating a new connection. Here’s the function that is in the generic service factory (Full code below)that does the trick:

public void HandleWCFException(Exception er)

{

if (er.GetType() == typeof(System.TimeoutException) || er.GetType() == typeof(System.ServiceModel.FaultException))

{

             ReOpenService();

}

       else

       {

             throw er;

}

}

 

public void ReOpenService()

{

if (_fact.State == CommunicationState.Opened)

       {

             try

              {

                    _fact.Close();

              }

              catch { }

            }

            _fact = new ChannelFactory<T>(_endPoint);

            _service = _fact.CreateChannel();

       }

}

So the implementation look s like this:

Try 

GenericSingleton(Of ServiceFactory(Of GC_WCF_Library.IGlobalDataAccessService)).GetInstance().Service.SaveDataSet(sql, ds, "OPS")

Catch servEx As System.Exception

If Not GlobalFunctions.HandleWCFErrors(servEx) Then

             Throw servEx

End If

End Try

 

There you can see the Service factory cached in the Generic Singleton class. We call a function called SaveDataSet on the service of type IGlobalDataAccessService. If an exception is caught, we check if it’s an WCF related exception. If so I reopen the service because it could be in the faulted state.

Also make sure you set the close timeout of your service to 2 or 3 seconds, because alse the closing of a service in faulted state could last a long time.

Here the complete code for the generic service factory:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;

 

namespace GP_Global

{

    public class ServiceFactory<T> where T : class

    {

        private T _service;

        private ChannelFactory<T> _fact;

        private string _endPoint;

 

        public ChannelFactory<T> Factory

        {

            get

            {

                if (_fact.State != CommunicationState.Opened)

                {

                    _fact = new ChannelFactory<T>(_endPoint);

                }

                return _fact;

            }

            set { _fact = value; }

        }

 

        public T Service

        {

            get

            {

                if (_fact.State != CommunicationState.Opened)

                {

                    _fact = new ChannelFactory<T>(_endPoint);

                    //fact.Open();

                    _service = _fact.CreateChannel();

                }

                //_service = fact.CreateChannel();

                return _service;

               

            }

            set

            {

                _service = value;

            }

        }

 

        public void HandleWCFException(Exception er)

        {

            if (er.GetType() == typeof(System.TimeoutException) || er.GetType() == typeof(System.ServiceModel.FaultException))

            {

                ReOpenService();

            }

            else

            {

                throw er;

            }

        }

 

        public void ReOpenService()

        {

            if (_fact.State == CommunicationState.Opened)

            {

                try

                {

                    _fact.Close();

                }

                catch { }

            }

            _fact = new ChannelFactory<T>(_endPoint);

            _service = _fact.CreateChannel();

        }

 

        public void InitFactory(string endpoint)

        {

            if (_service == null)

            {

                _fact = new ChannelFactory<T>(endpoint);

                _endPoint = endpoint;

                _service = _fact.CreateChannel();

            }

        }

    }

}


How to use the Find method with a generic list

You will have to implement a delegate method that will handle the comparison.

In this example I'm looking for a class of type Organ in a generic list of type List<Organ>. The match will be the organ guid.

 
Organ result = organsIn.Find(
    delegate(Organ or)
    {
        return or.OrganGuid == "guid" ? true : false;
    }
    );

This method will return the organ if found, or else null if not found.


Generic Singleton

Generics enables a whole new functionality. Combining this with the power of a singleton class creates something really interesting: a generic singleton class! So this way you can get a singleton instance of any type of class you want.

public class GenericSingleton<T> where T : class, new()

{

    private static T instance;

 

    public static T GetInstance()

    {

        lock (typeof(T))

        {

            if (instance == null)

            {

                instance = new T();

            }

            return instance;

        }

    }

}

Now I can create singleton instances of several classes with the same singleton class. I created a singleton instance of the LabCollectChannelFactory class and initiated the channels.

Deraeve.General.GenericSingleton<LabCollectChannelFactory>.GetInstance().InitChannels();

The LabColectChannelFactory will stay alive as long as the singleton lives. In the channel factory I implemented the IDisposable interface and I clear all channels when the Dispose method is called. This way I do not need to create an instance and initiate the channels each time a WCF call is made. This is only on the client side, the server side can also work with singleton class calls. You can use this singleton class for all your needs. The lock function ensure thread safety!

So now, after I initiated the channelfactory once, I can start calling the WCF functions:

List<User> AllActiveUsers = Deraeve.General.GenericSingleton <LabCollectChannelFactory>.GetInstance().UserManager.GetAllUsers();


Generic List

This is maybe the most beautifull feature of the new framework.

I use this List a lot. It has all the basic features a list needs. Sort function, find function etc. Here are some examples where I use this list:

if (list.ContainsKey(Functions.getValueFromComboBox(comboBox1)))
 

In this case I want to look up a value in the list, no more need to loop over the list! To get this value you'll have to loop over the list. You can use an easy foreach loop where you handle the comparison. Use the list with your own objects :

List <PCLOC> list= csLogic.GetComputersForRoom(_rect.Description);
 

or standard.Net objects :

List <string> computersInCS = new List<string>();

 

I don't see any reason why you should create an instance of an one dimensional array of any kind of object. Always use the Generic List. It has by default a Sort function, you can cast it to an array if you like (for databinding) and so on... Instead of using string [] sArray = new string [15]; use List<string> sList = new List<string>(); You might not need the sort or contains function now, but it could be handy later, or when specs change. The size of the list is dynamically increased. It works like an ArrayList, but there is no more boxing to be done. My advice is never use ArrayList or an array of objects when you can use the Generic list!

Josh Williams even showed in his post that an IList uses less space then an ArrayList. These are his results:             

         ArrayList    List<int>    Difference (%)
32-bit   19MB         8MB          237%
64-bit   39MB         8.1MB        481%

Read more about this on his blog.