Erik Lenaerts

Do, or do not. There is no try.

the making of the Service framework

This article describes the making of the Service framework based on the State design pattern which I described briefly in this post.

Why a State design pattern

When I had to write code that used some kind of state indication, I typically wrote a class with a private class variable of a certain enum type. This class had different methods (the "actions") that could be called by its clients. Every action could contain code that changed the state to another enum value. For example: 

public enum OrderState
{
    Started,
    Valid,
    Invalid,
    Processed
}

public class Order
{
    private OrderState _state;

    public Order()
    {
        _state = OrderState.Started;
    }

    public void AddProduct(Product product)
    {
    }

    public void Validate() 
    {
        // Check things here
        _state = OrderState.Validated;
    }

    public void Process()
    {
        // Process the order
        _state = OrderState.Processed;
    }
}

The drawback of this class becomes clear in a later development process, where the project sponsor starts changing and adding new the requirements.  Suddenly we could have a new state "shipped" or "packaged", etc. this would result into expanding the class and enum to support these new states. Additionally it is not so clear anymore what the valid transition paths are. Perhaps it is possible that an order can not be shipped if it ain't valid. So, in my code of the Ship method, I would have to test if the current state is valid.

It is obvious that this result into code that doesn't look pretty anymore after you've implemented the 30e change request of the order module.

The state design pattern described here, represents each of the enum values shown in the example as one class. When adding new states, you'll be adding new classes. The actions that are possible by the clients are then developed in each class seperatly resulting in small and clean classes. As added value, you determine exactly in your state classes to which other states you can lead to.  

Now, let's see how this works out for the Windows Service mini framework.

The fundaments

As described in theory we have the following players in a state design pattern:

  • Context
    • defines the interface of interest to clients
    • maintains an instance of a ConcreteState subclass that defines the current state.
  • State
    • defines an interface for encapsulating the behavior associated with a particular state of the Context.

I named the context class Service and basically it looks like:

namespace com.dotnet6.ServiceBase
{
    public class Service
    {
        private ServiceState _state;

        public Service()
        {
            _state = ServiceState.Halted;
        }

        public void Start()
        {
            _state.Start(this);
        }

        public void Stop()
        {
            _state.Stop(this);
        }

        public void Pause()
        {
            _state.Pause(this);
        }

        public void Resume()
        {
            _state.Resume(this);
        }

        internal void SetState(ServiceState state)
        {
            if (StateChanged != null)
                StateChanged(this, 
new StateChangedEventArgs(state.Status(), _state.Status())); _state = state; } } }

This class holds one private member _state that points to the current state or transition the service is in. Even if the number of states and transitions is fixed in a Windows Service concept, it doesn't stop us of using the state design pattern. When constructing the Service, it has a default state set to Halted. The different actions defined here (Start, Stop, Pause and Resume) won't perform any code of themself, they rely on the actual implementations defined in the different State classes, which we'll see in a moment. 

Note that this should be used in your Windows Service project. The Start, Stop, Pause and Resume methods, can be directly used from within your Windows Service project like this: 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using com.dotnet6.ServiceBase;

namespace WindowsService
{
    public partial class Service1 : ServiceBase
    {
        Service _service;

        public Service1()
        {
            InitializeComponent();
            _service = new Service();
        }

        protected override void OnStart(string[] args)
        {
            _service.Start();
        }

        protected override void OnStop()
        {
            _service.Stop();
        }
    }
}

So this makes the Windows Service project  pretty clean doesn't it.

The second class is the State class called ServiceState As mentioned above, this class encapsulates all the different actions.

namespace com.dotnet6.ServiceBase
{
    abstract class ServiceState
    {
        public static readonly ServiceState Running = new ServiceRunning();
        public static readonly ServiceState Pausing = new ServicePausing();
        public static readonly ServiceState Paused = new ServicePaused();
        public static readonly ServiceState Resuming = new ServiceResuming();
        public static readonly ServiceState Stopping = new ServiceStopping();
        public static readonly ServiceState Halted = new ServiceHalted();
        public static readonly ServiceState Starting = new ServiceStarting();

        /// <summary>
        /// Subclasses must decide what to do when the Host 
        /// starts the Engine.
        /// </summary>
        public virtual void Start(Service engine) { }

        /// <summary>
        /// Subclasses must decide what to do when the Host 
        /// stops the Engine.
        /// </summary>
        public virtual void Stop(Service engine) { }

        /// <summary>
        /// Subclasses must decide what to do when the Host 
        /// pauses the Engine.
        /// </summary>
        public virtual void Pause(Service engine) { }

        /// <summary>
        /// Subclasses must decide what to do when the Host 
        /// resumes the Engine.
        /// </summary>
        public virtual void Resume(Service engine) { }

        /// <summary>
        /// By default, discard notifications that the Engine
        /// finished starting, stopping and pausing
        /// </summary>
        public virtual void Complete(Service engine) { }
    }
}

This class acts as a base class for the different states and transitions we have (read the initial post on the different states and transitions). Secondly it adds public static readonly instances of every derived state/transition classes. This makes it a bit faster then recreating every state/transition when we move from one to to the other. All the virtual methods here can be found as the actions I defined earlier on the State Diagram. Since not every state or transition deals with every action, this is develop as a base class rather than an interface. Additionaly the state class usualy holds data shared by all child state classes. (which is not the case here, but just to let you know)

A derived class would override one or more of the virtual methods. This derived class would then implement the code that you need to perform in your Service. The example below shows the derived ServiceHalted state class:  

namespace com.dotnet6.ServiceBase
{
    class ServiceHalted : ServiceState
    {
        /// Starts the Engine when it was halted
        /// </summary>
        public override void Start(Service service)
        {
            service.SetState(ServiceState.Starting);
            // your code here...
            service.SetState(ServiceState.Running);
        }

        public override void Pause(Service engine)
        {
            throw new InvalidOperationException();
        }

        public override void Resume(Service engine)
        {
            throw new InvalidOperationException();
        }

        public override void Stop(Service engine)
        {
            throw new InvalidOperationException();
        }
    }
}

In the code above you see that during the Start action, we set the state of the Service class (context) to a transition (ServiceState.Starting is one of the private static readonly members as mentioned above). Then the code of this service would be executed and finally the state is set to Running.

Notice that each invalid action results in the existing InvalidOperationException. From MSDN library, this exception is used when "The exception that is thrown when a method call is invalid for the object's current state.", I would say, the perfect match for the job.

Besides the fact that there's another similar class for each state and transition mentioned, we're done with the fundaments here.

The ServiceEngine

Since this is a mini framework it implies that in some way or another you could apply this to your project without changing code. So, how could you define your real actions that needs to be performed if you shouldn't change the framework code.

I solved this dilemma by adding the ServiceEngine concept. In the mini framework the following Interface exists: 

namespace com.dotnet6.ServiceBase
{
    public interface IServiceEngine : IDisposable
    {
        void Start();
        void Stop();
        void Pause();
        void Resume();
    }
}

So, jour job is to implement this interface and write the code for every action. Then you can use this implementation in the mini framework by passing it on to the Service class during its construction:  

namespace com.dotnet6.ServiceBase
{
    public class Service
    {        
        private ServiceState _state;
        private IServiceEngine _serviceEngine;

        public IServiceEngine Engine
        {
            get { return _serviceEngine; }
            set { _serviceEngine = value; }
        }
        
        public Service(IServiceEngine serviceEngine)
        {
            _state = ServiceState.Halted;
            _serviceEngine = serviceEngine;
        }
      //...

As you can see, the initial service class now accepts a ServiceEngine which it will use later on to perform the required actions.

Ok, I here some of you thinking out aloud saying:

  • why does he uses a extensible model (State design pattern) with a fixed number of states and transitions?
  • why does he then locks down the model even further by externalizing the action code to a different component.

Well, basically you're right by asking these questions, however it is my believe that I managed to get a good balance between propper design and extensibility. You see, when we look at the state design pattern, it is indeed flexible to extend it. However, it always requires changes to the source code. Using some thoughts of component based development, I managed to make this framework flexible in its use and still keep the beaty of the state design pattern.

Finally

so, that's about it for the article. In the code I added some additional concepts like the IServiceProgress interface to report the progress percentage of a certain action to the client. Additionally I added a few events etc.

Download the Visual Studio 2005 solution here.

Comments

Erik Lenaerts said:

Introduction
In this post I want to share with you a mini framework I developed recently. In one of...
# May 24, 2006 1:14 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: