June 4, 2006

Windows Service Pattern

Use this template as an example for creating a service.
Note that XXX is the service implementation class, this class just integrates that service object into windows services.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Runtime.Remoting;

using Logging = log4net;

namespace XXX.service
{
  /// <summary>
  /// Main service class as created by the code generator.
  /// </summary>
  public class XXXService 
  {
    #region Logging

    private static readonly Logging.ILog log =   
        Logging.LogManager.GetLogger(typeof(XXXService));

    #endregion Logging

    /// <summary>
    /// 
    /// </summary>
    public static readonly string ServiceDisplayName =
        "XXXService";

    #region Private Fields

    /// <summary> 
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components
        = null;

    /// <summary>
    /// Did the service start up successfully
    /// </summary>
    private bool startSuccesful = false;

    #endregion Private Fields

    #region Constructor

    /// <summary>
    /// XXXService constructor.
    /// </summary>
    public XXXService()
    {
      // This call is required by the Windows.Forms
      // Component Designer.
      InitializeComponent();
    }

    #endregion Constructor

    #region Main/Initialise

    // The main entry point for the process
    static void Main()
    {
      System.ServiceProcess.ServiceBase[] ServicesToRun;
  
      // More than one user Service may run within the
      // same process. To add another service to this 
      // process, change the following line to
      // create a second service object. For example,
      //
      //   ServicesToRun = new
      //    System.ServiceProcess.ServiceBase[] { 
      //        new XXXService(),
      //        new MySecondUserService() };
      //
      ServicesToRun = new System.ServiceProcess.ServiceBase[] 
        { new XXXService() };

      System.ServiceProcess.ServiceBase.Run(ServicesToRun);
    }

    /// <summary> 
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
      components = new System.ComponentModel.Container();
      this.ServiceName = ServiceDisplayName;
    }

    #endregion  Main/Initialise

    #region IDispose Implementation

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null) 
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    #endregion IDispose Implementation

    #region Service Methods

    private bool IsDebugParameter(string arg)
    {
      var param = arg.ToUpperInvariant();

      return (param == "-DEBUG") || (param == "/DEBUG");
    }

    /// <summary>
    /// Set things in motion so your service can do its work.
    /// </summary>
    protected override void OnStart(string[] args)
    {
      // Allow us to be run in a debugger - for
      // development time support.
      if ((args.Length == 1) && IsDebugParameter(args[0]))
        Debugger.Launch();

      startSuccesful = false;
      string fileName = string.Empty;
      try
      { 
        log.Info("OnStart: Starting \'" + ServiceDisplayName<br> + "\'");

        System.IO.FileInfo fi = new System.IO.FileInfo(
            System.Windows.Forms.Application.ExecutablePath);
        System.Environment.CurrentDirectory = 
            fi.Directory.ToString();
        log.Info("Setting current directory to " 
            + System.Environment.CurrentDirectory);
        fileName = System.Windows.Forms.Application.ExecutablePath 
            + ".config";
        log.Info("Loading configuration from " + fileName);
        
        // If you have a remoting object that is 
        // initialised within the Config file       
        // initialise it here.
        // RemotingConfiguration.Configure(fileName);
            
        // Initialise 
        log.Info("OnStart: About to create XXX.");
        
        XXX xxx = new XXX(); // Service implementation class
        xxx.Initialise();
        
        // We assume that if the XXX is not constructed and 
        // initialised correctly it will throw an exception.
        // If we get to this point without an exception 
        // being thrown we assume 'alles ist gut'
        startSuccesful = true; 
        log.Info("OnStart: Started \'" + ServiceDisplayName 
            + "\' successfully=" + startSuccesful.ToString());
      }
      catch(Exception ex)
      {
        string errorMsg = 
          "Exception occured while starting service\'" 
            + ServiceDisplayName 
            + "\'. Expect an error message dialog");
        log.Fatal(errorMsg, ex);
        throw; // Results in error message: "XXX 
        // service on Local Computer started and 
        // then stopped. Some services stop if they 
        // have no work to do, for example, the 
        // Performance Logs and Alert service        
      }   
      if (startSuccesful)
      {
        // Tell the rest of the world we are running.
        ... 
      }
    }
 
    /// <summary>
    /// Stop this service.
    /// </summary>
    protected override void OnStop()
    {
      log.Info("OnStop: Stopping \'" + ServiceDisplayName<br> + "\'");
      
      if (xxx != null)
      {
        xxx.Dispose(); 
        ... 
      }
      
      if (startSuccesful)
      {
        // 
      }
      log.Info("OnStop: Stopped \'" + ServiceDisplayName<br> + "\'");
    }

    #endregion Service Methods

  }

No comments: