Dailycode.info

Short solution for short problems

Creating a service for your class library

During development, I always use a small WPF client to test the program, when test are going ok I create the service.

This week I used this tutorial twice, it only took me 1 hour to set it up correctly and needly (with event logging etc).

http://msdn.microsoft.com/en-us/library/zt39148a(v=vs.80).aspx

Logging I do with the aidf of a simple extra class (code found at the end of this post)

EventLogWriter.Instance.WriteToLog("Service Stopped", EventLogEntryType.Information);

I use this simple singleton class to help with the event logging:

 

/// <summary>

    /// Class enabling writing to the eventlog

    /// </summary>

    public class EventLogWriter

    {

        private System.Diagnostics.EventLog eventWriter;

 

        #region Singleton Pattern

 

        // Singleton.

        private static EventLogWriter _instance;

 

        /// <summary>

        /// Singleton Pattern.

        /// </summary>

        public static EventLogWriter Instance

        {

            get

            {

                if (EventLogWriter._instance == null)

                {

                    EventLogWriter._instance = new EventLogWriter();

                }

 

                return EventLogWriter._instance;

            }

        }

 

        #endregion

 

        /// <summary>

        /// Constructor

        /// </summary>

        public EventLogWriter()

        {

            // 

            // init eventWriter

            // 

            eventWriter = new EventLog();

            eventWriter.Log = "Application";

            eventWriter.Source = "SFIAutoMeasurementService";

        }

 

        /// <summary>

        /// Writes an entry to the eventlog

        /// </summary>

        /// <param name="msg">Message to write</param>

        /// <param name="entryType">Eventlog entry type</param>

        public void WriteToLog(string msg, EventLogEntryType entryType)

        {

 

            try

            {

                if (System.Diagnostics.EventLog.SourceExists("SFIAutoMeasurementService"))

                {

                    eventWriter.WriteEntry(msg, entryType);

                }

            }

            catch { }

 

        }

    }

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

            }

        }

    }

}


Generic WCF service factory. (In combination with generic singleton)

When you are working with WCF. You will find a need to have a factory that will initiate the services for you. To make it generic would be the best option, if your services do not differ to much from configuration implemtation. I will provide you with a class that will initiate any WCF service having its configuration in the config file or simply using the default configuration. It has a init function where you provide the endpoint configuration name.

public class ServiceFactory<T> where T : class

{

    private T _service;

    private ChannelFactory<T> fact;

    public T Service

    {

        get

        {

            if (fact.State != CommunicationState.Opened)

            {

                fact.Open();

            }

            _service = fact.CreateChannel();

            return _service;

        }

     

        set

        {

            _service = value;

        }

    }

    public void InitFactory(string endpoint)

    {

        if (_service == null)

        {

            fact = new ChannelFactory<T>(endpoint);

            _service = fact.CreateChannel();

         }

    }

} 

I used this in combination with a generic singleton, so I only initialize the service once and call the operations from the singleton:

 GenericSingleton<ServiceFactory<INurseryModuleService>>.GetInstance().InitFactory("MyEndPointConfig");

Then I just call the service operations like this:

GenericSingleton<ServiceFactory<INurseryModuleService >>.GetInstance().Service.TestNurseries(new TestNurseriesRequest());