Saturday, December 26, 2009

Workflow Without Windows Workflow

Hello, it has been a while since I wrote my last blog. Anyway, I am back again. I have a nice blog today, I have been working for a while with a team which his main target is to use everything Microsoft has released. It is a good thing sometimes and a very bad thing the other times. They read a "workflow" word in the requirements document, the first came to their mind was WF (Windows Workflow Foundation). The problem was so simple using WF would be over engineering. So, I decided to think of a more simple solution. As I am a Spring.NET Freak and I think we can't build an application without using it, I thought of using it :).

First, Let us create a State class first:

    public class State
    {
        private string _id;
        private string _name;
        private List<link> _links;

        public List NextStates
        {
            get
            {
                return Links.Select(l => l.State).ToList();
            }
        }

        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public List<link> Links
        {
            get { return _links; }
            set { _links = value; }
        }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public bool IsEndState
        {
            get
            {
                return Links.Count == 0;
            }
        }
    }

And a Link class:

    public class Link
    {
        //this condition will written used SPEL (Spring Expression Langauge)
        public string Condition { get; internal set; }
        public State State { get; internal set; }
    }

Then create the interface for the state machine:

    public interface IStateMachine
    {
        State InitialState { get; }
        State CurrentState { get; }
        void SetCurrentState(string id);
        bool Advance();
        List NextStates { get; }
    }
Then comes spring to the rescue, Spring here will used for 2 main tasks:
  1. Configuration File for our Workflow (State Machine): Keeps the state information and the transitions between states.
  2. Spring Expression will be used to define the transition rules between different states.
I decided to implement a simple interview process as an illustration for my small framework:

The spring configuration file for the mentioned process will be as follows:

<xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
 
  <object id="ExamToFirstInterview" type="SimpleStateMachine.Link, SimpleStateMachine">
    <property name="Condition" value="ExamScore >= 25"/>
    <property name="State" ref="FirstInterview" />
  <object>

  <object id="ExamToRejected" type="SimpleStateMachine.Link, SimpleStateMachine">
    <property name="Condition" value="ExamScore < 25"/>
    <property name="State" ref="Rejected" />
  <object>

  <object id="FirstInterviewToSecondInterview" type="SimpleStateMachine.Link, SimpleStateMachine">
    <property name="Condition" value="FirstInterviewAccepted"/>
    <property name="State" ref="SecondInterview" />
  <object>

  <object id="FirstInterviewToRejected" type="SimpleStateMachine.Link, SimpleStateMachine">
    <property name="Condition" value="!FirstInterviewAccepted"/>
    <property name="State" ref="Rejected" />
  <object>

  <object id="SecondInterviewToAccepted" type="SimpleStateMachine.Link, SimpleStateMachine">
    <property name="Condition" value="SecondInterviewAccepted"/>
    <property name="State" ref="Accepted" />
  <object>

  <object id="SecondInterviewToRejected" type="SimpleStateMachine.Link, SimpleStateMachine">
    <property name="Condition" value="!SecondInterviewAccepted"/>
    <property name="State" ref="Rejected" />
  <object>

  <object id="Exam" type="SimpleStateMachine.State, SimpleStateMachine">
    <property name="Id" value="exam"/>
    <property name="Name" value="Exam"/>
    <property name="Links">
      <list element-type="SimpleStateMachine.Link, SimpleStateMachine">
        <ref object="ExamToFirstInterview"/>
        <ref object="ExamToRejected"/>
      <list>
    <property>
  <object>

  <object id="FirstInterview" type="SimpleStateMachine.State, SimpleStateMachine">
    <property name="Id" value="first_interview"/>
    <property name="Name" value="First Interview"/>
    <property name="Links">
      <list element-type="SimpleStateMachine.Link, SimpleStateMachine">
        <ref object="FirstInterviewToSecondInterview"/>
        <ref object="FirstInterviewToRejected"/>
      <list>
    <property>
  <object>

  <object id="SecondInterview" type="SimpleStateMachine.State, SimpleStateMachine">
    <property name="Id" value="second_interview"/>
    <property name="Name" value="Second Interview"/>
    <property name="Links">
      <list element-type="SimpleStateMachine.Link, SimpleStateMachine">
        <ref object="SecondInterviewToAccepted"/>
        <ref object="SecondInterviewToRejected"/>
      <list>
    <property>
  <object>

  <object id="Accepted" type="SimpleStateMachine.State, SimpleStateMachine">
    <property name="Id" value="accepted"/>
    <property name="Name" value="Accepted"/>
    <property name="Links">
      <list element-type="SimpleStateMachine.Link, SimpleStateMachine">
      <list>
    <property>
  <object>

  <object id="Rejected" type="SimpleStateMachine.State, SimpleStateMachine">
    <property name="Id" value="rejected"/>
    <property name="Name" value="Rejected"/>
    <property name="Links">
      <list element-type="SimpleStateMachine.Link, SimpleStateMachine">
      <list>
    <property>
  <object>


  <object id="InterviewProcess.InterviewStateMachine" type="InterviewProcess.InterviewStateMachine, InterviewProcess">
    <property name="AllStates">
      <list element-type="SimpleStateMachine.State, SimpleStateMachine">
        <ref object="Exam"/>
        <ref object="FirstInterview"/>
        <ref object="SecondInterview"/>
        <ref object="Accepted"/>
        <ref object="Rejected"/>
      <list>
    <property>
    <property name="InitialState" ref="Exam"/>
  <object>

  <object id="SimpleStateMachine.IStateMachineManager" type="SimpleStateMachine.StateMachineManager, SimpleStateMachine">
  <object>

<objects>


Quite Simple? I think so :) Let us try it.



At the end I am not saying that this a replacement for windows workflow foundation is a very powerful framework but I am only pushing people to think outside of the box.

You can refer to the full source code here and don't forgot that I used Visual Studio 2010 Beta 2. Good Luck!

The initials of my blog are WWWW, isn't this cool? :D ... maybe this will be the next WWW ;).

Friday, May 8, 2009

Using WCF and Spring.NET to Scale Your Architecture

Windows Communication Foundation (WCF) is more than just web services. Most of the .NET developers think of it as a replacement for old ASMX web services. Today I am going to show you how I am going use it in a different way. I am going to use it to distribute different components of a system to be run separately on different machines without re-compilation of your code. You can do this based on your needs and the hardware available.

First, Let us define the problem we are trying to solve. Assume that you are working on an application that part of its logic is to compute a complex operation. This operation can not be simplified and it consumes most of the application time. Your default deployment will be as following:


This deployment model will introduce a bottleneck to your application. What I have in mind is to deploy the application on a server and the complex component on another one. This way you can distribute the processing across your servers. Then the deployment will be as following:


Let us see a simple example for the implementation of the following components. This our service contract:

[ServiceContract]

public interface ICalcEngine

{

        [OperationContract]


        Operation CalculateOperation(Operation operation);

}

We will use spring to load your component hosted in memory as mentioned in the first deployment model.

      <object name="CalcEngineWCF.ICalcEngine"

              type="CalcEngineWCF.CalcEngine, CalcEngineWCF"/>

My proposed solution will allow you change the deployment model without changing a line of code in your application as mentioned in the second deployment model. You will deploy your complex component as a service on a remote host. In this case spring configuration in the client side (the main application server) will be as following:

      <object name="CalcEngineWCF.CalcEngineFactory"

              type="CalcEngineWCF.CalcEngineFactory, CalcEngineWCF">

        <property name="Address" value="http://remote-server:8000/CalcEngine/Service"/>

      </object>


      <object name="CalcEngineWCF.ICalcEngine"

                        type="CalcEngineWCF.CalcEngine, CalcEngineWCF"

                        factory-method="CreateWCFInstance"

                        factory-object="CalcEngineWCF.CalcEngineFactory"/>

I hope this will be clear enough for you to be able to apply this model in your applications.

You can also refer to a working example here. The mentioned solution contains 3 projects:

  1. CalcEngineWCF: Our complex component that needs to be distributed.
  2. WCFHost: Remote application that will host CalcEngineWCF.
  3. WCFClient: The main application server. Its name might be confusing because it acts as a client to the remote host.