Wortzel's blog

.Net (2.0, 3.0, 3.5), C#, Asp.net, Com+, GIS(ESRI Software), Management, Analysis & Design, Life, Trips, And more...
Host multiple services in windows service (on-line WCF services and batch services)
In the last sprint we (Ori – my teammate and me) had a task to create an infrastructure to manage some common processes in our systems. The processes can be a batch, schedule tasks and on-line services (WCF).
Let see some of our processes:
  • We have a background process (aka "Directory monitoring") which monitors a specific directory in predefined interval and checks for new incoming files. When a new file arrives, the process wakes-up and checks the file name by regular expression. Then it associates the relevant handler for this file.
  • We have a reports creator process which run every few minutes/hours and create a report tables.
  • And for dessert, we have a WCF service that gets notifications from several systems. For each notification it associate handler that responsible to take care for the implementation. 
At the design stage, we defined some requirements for this infrastructure:
  • Easy to deploy: The deploy process should be very simple.
  • Scalability: We should have the ability to create multiple instances for this processes manager in the same computer (In case that we install several applications on the same computer).
  • Easy to development: Rapid development for new processes with minimal knowledge about the low level implementation.
  • Isolation: Each one of this processes will run and manage itself in a speared thread (unless there are cases that we need more control on synchronization between several processes). 
So let's start:

Step 1: Create service interface

In order to give our services the ability to control their life cycle we defined an interface with two methods. Every service that wants to be included in the services list must implement it. In the Start() method the service should open its private thread, initiate wcf and ext. In the Stop() method  it should give the option of finishing the executing of the current service in immutable state (Instead of terminating the services thread). 
public interface IService
{   
    void Start();   
    void Stop();
}



Step 2: Create service configuration

In this step we'll create a configuration handler (with some helper classes) and define the service configuration format that will be stored in the configuration file.This code defines a new configuration section in our configuration file:
<configSections>       
    <
section name="serviceSettings
        type
="WindowsServiceHost.ServiceSettingsHandler,
        WindowsServiceHost
"></section>
</configSections>
It'll give us the ability to add a new "serviceSetting" section with the "ServiceSettingsHandler" class handler and to work strongly typed with our configuration section. We can add multiple services in this section, but remember that each one of them must implement the IService interface. For example we'll insert two service declarations into this file. The first one will be a periodic service and the second will be a wcf service.
<serviceSettings>
    <service assembly="Wortzel.ApplicationServices.dll"  
        className
="Wortzel.ApplicationServices.BatchServices.PeriodicService" />
    <service assembly="Wortzel.ApplicationServices.dll" 
        className
="Wortzel.ApplicationServices.SynchronousServices.SimpleCalculator" />
</serviceSettings> 

Step 3: Implement the service

We implemented the first service in a single class which opens a new thread which wakes-up every some interval and execute something. For a better design you should prefer to spread the scheduling from the service logic.   
public class PeriodicService:IService
{   
    private Thread _Thread;
   
    private bool _IsActive = true;
   
    private int _RunningInvervalInMillisecond = 5000;
   
 
    #region
IService Members    
   
    public
void Start()
   
    {
       
        _Thread = new Thread(new ThreadStart(this.ThreadStart));
       
        _Thread.Start();
   
    }
    

    public void Stop()
   
    {
       
        _IsActive = false;
   
    }
    

    #endregion
    

    public void ThreadStart()
   
    {
       
        while (_IsActive)
       
        {
           
            Execute();
            
            //Execute something in some interval
           
            Thread.Sleep(_RunningInvervalInMillisecond);
       
        }
       
        _Thread.Abort();
   
    }
    

    private void Execute()
   
    {

        //Executing...

        Trace.Write("Processing...");      

    }
}
For the second service we defined two classes. In the first class we declared the service contract:
[ServiceContract]
public interface ICalculator
{    
    [OperationContract]
   
    int Plus(int number1, int number2);
    

    [OperationContract]
   
    int Minus(int number1, int number2);
    

    [OperationContract]
   
    int Multiple(int number1, int number2);
    

    [OperationContract]
   
    double Divide(int number1, int number2);
}
And in the second class we implemented the service itself.
public class SimpleCalculator : WcfWindowsServicesHost, ICalculator
{   
    public SimpleCalculator()
   
    : base(typeof(SimpleCalculator))
   
    { }
    

    #region
ICalculator Members    

    public int Plus(int number1, int number2)
   
    {
       
        return number1 + number2;
   
    }
    

    public int Minus(int number1, int number2)
   
    {
       
        return number1 - number2;
   
    }
    

    public int Multiple(int number1, int number2)
   
    {
       
        return number1 * number2;
   
    }
    

    public double Divide(int number1, int number2)
   
    {
       
        return (number2 != 0) ? (number1 / number2) : 0;
   
    }
    

    #endregion
}
You should notice that the developer that wrote this service didn't need to know the lower infrastructure which takes care about the service hosting.  

Step 4: Create services hosting engine

In this step we need to create an engine that will manage all the services. This engine reads the services declarations from configuration file, creates an instance for each one of them using the IService interface, handles the start and stop operations of the entire services.
public class ServicesLoader : ServiceBase
{   
    private ICollection<IService> _Services;
    
    private ICollection<IService> GetServices()
   
    {
       
        List<IService> services = new List<IService>();

        foreach (ServiceSetting serviceSetting in 

            ServiceSettingManager.GetServiceSettings())       
        {
           
            Type classType = Assembly.LoadFrom(serviceSetting.Assembly)
               
               .GetType(serviceSetting.ClassName);
           
            services.Add((IService)Activator.CreateInstance(classType));
       
        }
       
        return services;
   
    }
    

    protected override void OnStart(string[] args)
   
    {
       
        _Services = GetServices();
       
        foreach (IService service in _Services)
       
        {
           
            service.Start();
       
        }
   
    }
    

    protected override void OnStop()
   
    {
       
        foreach (IService service in _Services)
       
        {
           
            service.Stop();
       
        }
   
    }
    

    public void StartService()
   
    {
       
        OnStart(new string[] { });
   
    }
    

    public void StopService()
   
    {
       
        OnStop();
   
    }
    

    static void Main()
   
    {
       
        ServiceBase[] ServicesToRun;
       
        ServicesToRun = new ServiceBase[]
             
        {
                   
            new ServicesLoader()
             
        };
       
        ServiceBase.Run(ServicesToRun);
   
    }
}

Step 5: Create service installer

In order to host the service inside the windows services, we must create an installer. The RunInstaller attribute is required for let the windows installer know where it can find the start point of the installation.
[RunInstaller(true)]
public class ProjectInstaller : Installer
{   
    private ServiceProcessInstaller process;
   
    private ServiceInstaller service;
   

    public ProjectInstaller()
   
    {
       
        process = new ServiceProcessInstaller();
       
        process.Account = ServiceAccount.LocalSystem;
       
        service = new ServiceInstaller();
       
        service.ServiceName = "WindowsServiceHostWCF";
       
        service.StartType = ServiceStartMode.Automatic;
       
        Installers.Add(process);
       
        Installers.Add(service);
   
    }
}
After we created the installer class you can install the service loader and to turn it to a normal windows service. To accomplish this task you can use the installUtil.exe utility.  

Step 6: Start the service…

In this step all what you need to do is to start your new service manager. You can do it by opening the windows services panel or in the shorter way by using the command-line utility "net start [Service Name]". 

Conclusions:

This infrastructure gives the developer an abstract layer to implement multiple services (on-line services and batch services) which hosts inside a window service. It's also approving the rapid development when adding new services. 

You can download a complete source code with full samples from the link above.

Published Friday, December 14, 2007 2:51 PM by Avi Wortzel

Comments

# re: Host multiple services in windows service (on-line WCF services and batch services)@ Friday, September 26, 2008 12:29 PM

Awesome. Prety close to what I was looking for.

Needed a "real" ServiceHost manager. Looks like this could lead me in the right direction.

Bill

# re: Host multiple services in windows service (on-line WCF services and batch services)@ Thursday, January 15, 2009 4:15 AM

thank you!

wavexiang