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();

            }

        }

    }

}



blog comments powered by Disqus