preface - home - srujana-shiva.net€¦  · web viewyou may have wcf and wpf ... this article is a...

57
Introduction This article describes how to create and run a State Machine Workflow in Windows Workflow Foundation (formerly WWF, or just WF) which comes bundled with .NET Framework 3.0 and above. Before we get started, if you are new to WF and .NET Framework 3.0, I think you'd better take a look at some articles about WF. Here are some useful links: http://wf.netfx3.com/ http://msdn2.microsoft.com/en-us/netframework/aa663322.aspx Background In order to create WF applications, you need to install some required packages/tools. These are: 1. .NET Framework 3.0 Runtime 2. Visual Studio 2005 Professional Edition 3. Windows Workflow Foundation extensions for Visual Studio 2005 4. Windows Communication Foundation (WCF,formerly Indigo) & Windows Presentation Foundation (WPF,formerly Avalon) The fourth one is optional in fact. However, there may be some troubles and you may get some weird error if you don't have WCF and WPF installed on your development computer. So, I suggest you have WCF and WPF installed too. Now, I want to demonstrate a daily life example. Assume that you want to lock something (A file, a safe, a door,...etc.). This locker has exactly 2 different states: LOCKED and UNLOCKED. And you change its state by opening and closing. In our application, we call some methods to change workflows state; from/to LOCKED to/from UNLOCKED. Using the Code Let's dig in the code. First we open .NET Visual Studio 2005. In the Start Page window, click Project from Create row. In the New Project window, extend Visual C# node, then select Workflow. There are many applications but we will create a state machine application so we select State Machine Workflow Library and name it FirstStateMachineWorkflow. Then click OK.

Upload: ngodieu

Post on 29-Aug-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Introduction

This article describes how to create and run a State Machine Workflow in Windows Workflow Foundation (formerly WWF, or just WF) which comes bundled with .NET Framework 3.0 and above.

Before we get started, if you are new to WF and .NET Framework 3.0, I think you'd better take a look at some articles about WF. Here are some useful links:

http://wf.netfx3.com/ http://msdn2.microsoft.com/en-us/netframework/aa663322.aspx

Background

In order to create WF applications, you need to install some required packages/tools.

These are:

1. .NET Framework 3.0 Runtime 2. Visual Studio 2005 Professional Edition 3. Windows Workflow Foundation extensions for Visual Studio 2005 4. Windows Communication Foundation (WCF,formerly Indigo) & Windows

Presentation Foundation (WPF,formerly Avalon)

The fourth one is optional in fact. However, there may be some troubles and you may get some weird error if you don't have WCF and WPF installed on your development computer. So, I suggest you have WCF and WPF installed too.

Now, I want to demonstrate a daily life example. Assume that you want to lock something (A file, a safe, a door,...etc.). This locker has exactly 2 different states: LOCKED and UNLOCKED. And you change its state by opening and closing. In our application, we call some methods to change workflows state; from/to LOCKED to/from UNLOCKED.

Using the Code

Let's dig in the code.

First we open .NET Visual Studio 2005. In the Start Page window, click Project from Create row. In the New Project window, extend Visual C# node, then select Workflow. There are many applications but we will create a state machine application so we select State Machine Workflow Library and name it FirstStateMachineWorkflow. Then click OK.

Page 2: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

After creating the application, your designer window should look like this:

NOTE: If you can't see Workflow1.cs[Design] or if there is something wrong with the steps above, go check the requirements. Probably you missed some of them or they are not installed properly.

Page 3: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Now, we need an interface to declare the events. Right click the project -> Add -> New Item -> Select Interface and name it ILocker.cs. Write the code below to the interface.

Collapse Copy Codeusing System;using System.Collections.Generic;using System.Text;using System.Workflow.Activities;

namespace FirstStateMachineWorkflow{ [ExternalDataExchange] public interface ILocker { event EventHandler<ExternalDataEventArgs> Lock; event EventHandler<ExternalDataEventArgs> Unlock; }}

Lock and Unlock are our events which make the workflow change its state. Now we need a class implementing this interface and having the methods to fire the events. Right click the project -> Add -> New Item -> Select Class and name it Locker.cs. Write the code given below to the class:

Collapse Copy Codeusing System;using System.Collections.Generic;using System.Text;using System.Workflow.Activities;

namespace FirstStateMachineWorkflow{ [Serializable] public class Locker : ILocker { public event EventHandler<ExternalDataEventArgs> Lock; public event EventHandler<ExternalDataEventArgs> Unlock;

public bool lockerState = false;

public bool LockIt(Guid InstanceID) { if (this.Lock != null) { this.Lock(this, new System.Workflow.Activities.ExternalDataEventArgs(InstanceID)); return true; } else { return false; } }

public bool UnlockIt(Guid InstanceID) { if (this.Unlock != null) { this.Unlock(this, new System.Workflow.Activities.ExternalDataEventArgs(InstanceID)); return false; } else

Page 4: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

{ return true; } } }}

As you see Locker class uses events to change the workflows state. These two methods (LockIt and UnlockIt) are going to be used by the host application.

Now, we go back to our workflow designer window. Open Workflow1.cs[Designer]. Click the state and in the properties window, change its name as Unlocked. On the right-hand side tool box, drag and drop EventDrivenActivity on the state. Change its name as LockEvent and double-click. This will open a new design window. On the toolbox, drag and drop HandleExternalEventActivity and change its name to HandleLockEvent. This will help us to handle the event fired by the host application. While HandleLockEvent is selected, in the properties window, click the InterfaceType property. A new window will open, there, select ILocker. This is needed to define which events are handled by which event handler. Now, above in the properties window, select Lock in the EventName combo-box. So far, we made the Lock event to be handled by this handler. But after handling, we want to write a message to the console stating which event is handled. To do this, drag and drop a CodeActivity from toolbox, name it LockedCode, double click it. You will go to Code View. There in the LockedCode_ExecuteCode method, write the code below:

Collapse Copy Codeprivate void WriteState_ExecuteCode(object sender, EventArgs e){ Console.WriteLine("Locked!!!");}

So, we handled the event, wrote the message, what next? Now we must do something to change the current state. From toolbox drag and drop a new StateActivity to Workflow1.cs[Design] and name it as Locked. Now in HandleLockedEvent view, drag and drop SetStateActivity under code activity. Name it as SetLocked and in the properties window, set TargetStateName as Locked.

Do the same steps for Locked state reversed and properly. Drag drop HandleUnlockEvent, add UnlockedCode and SetUnlocked to Unlocked.

After all these changes, your Workflow1.cs[Designer] should look like this :

Page 5: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Now it is time to add a host application to the solution.

NOTE : Remember, Windows Workflows (be it State Machine or Sequential Workflow) cannot run by themselves. They need an external host application. The application may be a Windows application, Console Application or Web Application (ASP.NET).

Right click solution -> Add -> New Project. In the New Project window, select Visual C# and select Console Application , name it Test.

After creating the console application, right click on the console application and select Set As StartUp Project. We must add reference to use workflow methods. To do that, right click References -> Add Reference -> In .NET tab, select System.Workflow.Activities, System.Workflow.Runtime, System.Workflow.ComponentModel.

Page 6: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

We need FirstStateMachineWorkflow reference also. References -> Add Reference -> In Projects tab, select FirstStateMachineWorkflow and click OK.

In Program.cs, write the code given below to run the workflow:

Collapse Copy Codeusing System;

Page 7: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

using System.Collections.Generic;using System.Text;using System.Workflow;using System.Workflow.Activities;using System.Workflow.Runtime;using FirstStateMachineWorkflow;

namespace Test{ class Program { static void Main(string[] args) { WorkflowRuntime workflowruntime = new WorkflowRuntime(); Locker locker = new Locker(); Guid locker_ID = Guid.NewGuid(); Dictionary<string,object> Params = new Dictionary<string,object>(); ExternalDataExchangeService ExDateExchService = new ExternalDataExchangeService(); workflowruntime.AddService(ExDateExchService); ExDateExchService.AddService(locker); WorkflowInstance wfinstance = workflowruntime.CreateWorkflow( typeof(Workflow1) , Params , locker_ID ); wfinstance.Start();

locker.LockIt(locker_ID);

Console.ReadLine();

locker.UnlockIt(locker_ID);

Console.ReadLine(); } }}

Here, WorkflowRuntime object is used to configure workflow properties, Locker is our class implementing interface. Dictionary is to pass parameters to workflow. However, we don't have any parameters in our example.

Collapse Copy CodeWorkflowInstance wfinstance = workflowruntime.CreateWorkflow( typeof(Workflow1) , Params , locker_ID );wfinstance.Start();

WorkflowInstance is used to create an instance of our Workflow1 workflow and then it is started with the wfinstance.Start method.

After running this application, you should get this console window:

Page 8: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Points of Interest

As I mentioned before, WF itself is not enough to create WF applications. You may have WCF and WPF installed as well as WF.

And to summarize the steps again:

1. Create a workflow statemachine application. 2. Write an Interface for transitions between states (Write events). 3. Write the [Serializable] class implementing the interface events and calling

them in functions.

4. Create a host application which uses the class and starts workflow.

Page 9: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Preface

This is second in series of articles on Windows Workflow Foundation that will help every Joe to start from ABC, and as this article series progresses, make steady rise to steeple of expertise. The first article of this series "Jump Start Windows Workflow Foundation" published last week.

Introduction

This article will start from where last article ended, though we will run a quick overview for buddies who joined our party from this article. Windows Workflow Foundation (WF, to save typing efforts) is one of four super stars that hit the limelight with .NET 3.0. It has a programming model, activity library, services, runtime a tool, an engine, and a design that helps programmers from separating sequence and state machine based logic from core business functionality. Critics have speculated about WF as one of the major changes in middle-tier since the arrival of COM+ / DTC and since Microsoft has plans for supporting it for current (Windows XP, 2003) and future (Vista) Windows releases; use and popularity of WF is only going to increase.

Looking around the software arena makes us realize almost all software solutions have certain tasks (call them activities) to perform either sequentially or on the basis of some events (call them state-machine based). Thus in our lingo, we will re-phrase above sentence as: almost every application has 'workflow' in it with number of 'activities' in it, these workflows may execute in a 'sequential' manner, or may be 'state-machine' based.

Summing this up, here are the precise definitions of terms we lately encountered.

Workflow: Series of steps, decisions and rules needed to complete a specific task.

Activities: Tasks/steps that define the workflow, these are basic building blocks of workflow.

There can be two types of workflows:

Sequential: series of activities are called in order. State machine: activities are called on the basis of 'state' of different

parameters.

In the last article, we made a sequential workflow application. This time we are here to create a 'state machine'-based application.

What and Why - State Machine workflows

"State machine" lit a bulb in the mind of many of us computer graduates and take us to those nice memories of university/college days. Well don't feel too nostalgic, come back to present days - you are going to learn some very exciting things today, so feel good about it and enjoy!

State machines have been in who's who of computer science since long. Programmers use them to model states, events and transitions. There are three key concepts involved here:

1. State: a situation 2. Event: a stimulus 3. Transition: transfer of control from one 'state' to another, in consequence of some

'event'

Page 10: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

In above diagram, control moved from 'State A' to 'State B' on occurrence of 'Event 1' with transition shown using arrow. Some action takes place after event is fired and transition is made. WF helps in programming solutions that have state machines in it by providing easy-to-used designer interface, activities and programming model.

Our Sample Scenario

We will develop a simple 'Purchase Ordering' based application. Each PO can have any of three states;

Created Authorized Sent

This will be modeled using WF Designer and simple code will be added to show how the life of a programmer is made easy by WF while programming event-driven (state machine-based) programs.

Welcome to the Playing field, let's start the game

Open up Visual Studio 2005 IDE and click on 'New Project'. Select 'State Machine Workflow Console Application' as project type.

Page 11: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Select an appropriate project name (mine is 'FirstWFStateMachine'). Check 'Location' of project on the disk drive and click 'OK'. 'Workflow Designer' will open up now. Workflow will have only one 'State Activity' in it currently. Change its name to 'POInitialState' in 'Properties' dialog. Add three more 'State Activities' by dropping and dragging from the toolbox and name them as 'POCreated, POAuthorised, POSent'. Right-click on 'POInitialState' and select 'Select as Initial State', right-click 'POSent' and select 'Set as Completed State'. Your screen should look like the following now.

Page 12: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

That's done; we have defined all four 'states' in our program. Next, we will define 'events' that will be processed in each state. Now we will play with some code in our program. First define an interface for all three states.

Collapse Copy Code

[ExternalDataExchange]public interface IPOService{ event EventHandler<POStateChangedEventArgs> POCreated; event EventHandler<POStateChangedEventArgs> POAuthorised; event EventHandler<POStateChangedEventArgs> POSent; }

Next we will define our class for Purchase Order. It will have two attributes only (to keep it simple) Item ID and Due Delivery Date. Thus, a purchase order will be generated for a product only.

Collapse Copy Code

[Serializable]public class PO{ public PO() {} public PO(string _ItemID, DateTime _DueDeliveryDate)

{

ItemId = _ItemID;

Page 13: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

DueDeliveryDate = _DueDeliveryDate; } private string ItemId; private DateTime DueDeliveryDate;

public string ItemCode { get { return ItemId; } set { ItemId = value; } }

public DateTime PODueDeliveryDate { get { return DueDeliveryDate; } set { DueDeliveryDate = value; } }}

Hold on a second here and let's ponder over why did we add [Serializable] and [ExternalDataExchange] above. Since it may take hours if not days, or even months for some PO to get authorized and sent (a Manager will catch a flight for Hawaii before authorizing PO!), worflows gets persisted on database. To achieve this behavior, one of the prerequisites is that your classes must be "serializable", thus the addition of [Serializable] directive. [ExternalDataExchange] must be added to our interface to denote it's a 'message contract' between runtime and workflow.

Look at IPOService interface again. POStateChangedEventArgs expects to have information for workflow to continue. Thus the object of PO will be passed to it.

Collapse Copy Code

[Serializable]

public class POStateChangedEventArgs : ExternalDataEventArgs{ public POStateChangedEventArgs(Guid instanceID, PO po) : base(instanceID) { _PO = po; WaitForIdle = true; }

private PO _PO;

public PO PO { get { return _PO; } set { _PO = value; } }}

Instance Id is GUID for each workflow instance (which subsequently means for each purchase order) created by runtime.

The service that implements the IPOService interface will raise events when the status of a PO changes. Let's implement it now and provide simple methods that raise events.

Collapse Copy Code

public class POService : IPOService{ public event EventHandler<POStateChangedEventArgs> POCreated;

Page 14: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

public event EventHandler<POStateChangedEventArgs> POAuthorised; public event EventHandler<POStateChangedEventArgs> POSent;

public void CreatePO(Guid id, PO po) { if (POCreated != null) { POCreated(null, new POStateChangedEventArgs(id, po)); } }

public void AuthorisePO(Guid id, PO po) { if (POAuthorised != null) { POAuthorised(null, new POStateChangedEventArgs(id, po)); } }

public void SendPO(Guid id, PO po) { if (POSent != null) { POSent(null, new POStateChangedEventArgs(id, po)); } }}

Let's jump back to Workflow Designer now. We created a simple purchase ordering class, contracted between workflow and runtime (IPOService) and events. Now lets select 'Event Driven' activity from toolbox and drop at 'POInitialState'. Name it as 'OnPOCreate'. It should look like:

'OnPOCreate' should have some series of activities that would be fired when this event is fired. For that, double-click it, this will open up details of the activity.

Page 15: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

<

It also shows breadcrumb navigation at top-let corner of screen. Here we can see 'Event Driven' is just like any other sequential workflow, it can hold number of child activities. However, there is one restriction, the first activity within Event Driven activity must be Delay, HandleExternalEvent or WebServiceInput activity. This is because first activity must have implemented IEventActivity interface, which is only true for above mentioned three activities. Since we need to respond to external event (PO got created!) we will drag-drop the 'HandleExternalEvent' activity. Change its name to 'handlePOCreatedEvent', click on ellipses to select Interface 'IPOService', select 'Eventype' from drop down.

Page 16: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Now, select 'Set State' activity and drag-drop this on designer window. In properties window, assign 'POCreatedState' as 'Target state'. This will create a link from 'POInitialState' to 'POCreatedState'.

Following same procedure, we will model other state transitions in Workflow. In the end, it will look like following:

Page 17: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Can you believe, we are almost done! Just add this simple code in Program.cs that will act as runtime host. We will add simple Console.ReadLine and Console.WriteLine statements to create console interactive environment, where user is prompted for item ID and due delivery date for creating a purchase order. Then user is prompted for PO authorization, and until she says yes to it, PO's state doesn't change. Similar is the case with PO sent. In the end, we added a simple method for printing current and possible future transitions at each state of Workflow. This is achieved using 'PossibleStateTransitions' collection in Workflow instance.

Collapse Copy Code

private static void DumpStateMachine(WorkflowRuntime runtime, Guid instanceID){ StateMachineWorkflowInstance instance = new StateMachineWorkflowInstance(runtime, instanceID);

Console.WriteLine("Workflow ID: {0}", instanceID); Console.WriteLine("Current State: {0}",

instance.CurrentStateName);

Console.WriteLine("Possible Transitions: {0}", instance.PossibleStateTransitions.Count); foreach (string name in instance.PossibleStateTransitions) { Console.WriteLine("\t{0}", name); }}

Following are screen shots of running application:

Page 18: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

What We Learned

This article followed a jump start approach to explore 'State-Machine' based workflows. We picked a practical problem and tried resolving it using WF by defining states (using State activity), events (Event Driven activity and Handle External Event activity) and transitions (SetState activity). A simple console application hosted our workflow runtime to provide interactive feel to user.

Page 19: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

A good Amount of examples can be seen in this link

http://msdn.microsoft.com/en-us/library/ms735967.aspx

Page 20: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

For ASP.net using WWF

Contents

Introduction Navigational Logic and Rules Setting Up the Workflow Runtime Navigational Workflow Architecture Creating and Starting a New Navigational Workflow The Previous and Next Events: How Navigation Works

o Introduction o Explanation

Synchronization, Self-Healing, and the Browser Back/Forward Buttons o Browser Back/Forward Buttons o Synchronization and Self-Healing

Error Pages Persistence and Long Running Workflows Skipping Between Pages Running the Code History

Introduction

What is a Navigational Workflow? In a nutshell, a Navigational Workflow is a method of describing navigational logic for an application as well as the rules that ensure that logic is adhered to. Any application that must follow some sort of process flow requires a Navigational Workflow.

This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating website called "World Wide Dating". The host application is written in ASP.NET, and the Navigational Workflow is written using Windows Workflow Foundation.

Navigational Logic and Rules

World Wide Dating has six main pages:

1. Default.aspx (the start page) 2. Basics.aspx 3. Appearance.aspx 4. Lifestyle.aspx 5. Interests.aspx 6. Complete.aspx (the last page)

The page that first appears when the application starts is default.aspx. From here, the user can create, rehydrate, and delete Navigational Workflows. The "natural flow" of the workflow is:

Page 21: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

In addition to the above, the workflow allows jumping from one State to another if, and only if, the user has visited that State already using the "natural flow" defined above. To give a concrete example, imagine having navigated the following scenario: default => basics => appearance => lifestyle. The user is now in the lifestyle State. From here, they can follow the workflow "naturally" and go to the interests State or back to the appearance State. In addition, the user can choose to skip to the basics State. The user cannot, however, skip to the complete State, because that State has not yet been visited. If the user attempts to prematurely skip to a State, then they are redirected to an error page (more on error pages later).

Setting Up the Workflow Runtime

Because this is an ASP.NET web application, we must load the ManualWorkflowSchedulerService into the workflow runtime. If we do not, then workflows will execute asynchronously and the host application might return before the workflow is done executing. This is set up inside the web.config:

Collapse Copy Code

<add type= "System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

There is considerable overhead that gets introduced in creating and starting the workflow runtime with each request. To avoid this, we can load the workflow runtime just once during application startup, and shut it down when the application ends. This is done in Global.asax.cs:

Collapse Copy Code

protected void Application_Start(object sender, EventArgs e){ // create an instance of workflow runtime, // loading settings from web.config WorkflowRuntime workflowRuntime =

Page 22: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

new WorkflowRuntime( WorkflowManager.WorkflowRuntimeKey);

// add the external data exchange service to the // runtime to allow for local services ExternalDataExchangeService exchangeService = new ExternalDataExchangeService( WorkflowManager.LocalServicesKey); workflowRuntime.AddService(exchangeService);

// start the workflow runtime workflowRuntime.StartRuntime();

// save the runtime for use by the entire application Application[WorkflowManager.WorkflowRuntimeKey] = workflowRuntime;}

protected void Application_End(object sender, EventArgs e){ // obtain reference to workflow runtime WorkflowRuntime workflowRuntime = Application[WorkflowManager.WorkflowRuntimeKey] as WorkflowRuntime;

// stop the runtime if (workflowRuntime != null) { workflowRuntime.StopRuntime(); workflowRuntime.Dispose(); }}

Navigational Workflow Architecture

Our Navigational Workflow is built using the State-Machine workflow template. Each StateActivity in the Navigational Workflow maps to a corresponding ASPX page. This mapping is inside the web.config:

Collapse Copy Code

<elements> <element stateName="InitialState" pageName="default.aspx" weight="0" /> <element stateName="BasicsState" pageName="basics.aspx" weight="10" /> <element stateName="AppearanceState" pageName="appearance.aspx" weight="20" /> <element stateName="LifestyleState" pageName="lifestyle.aspx" weight="30" /> <element stateName="InterestsState" pageName="interests.aspx" weight="40" /> <element stateName="CompleteState" pageName="complete.aspx" weight="50" /></elements>

The structure of the application is represented in the following diagram:

Page 23: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The ASP.NET host application uses the Workflow Manager as a wrapper to communicate with the Navigational Workflow. All requests into the Navigational Workflow are delegated through the Workflow Manager.

Creating and Starting a New Navigational Workflow

The host application makes the following call to start a new workflow:

Collapse Copy Code

_workflowManager.StartNewWorkflow();

The StartNewWorkflow method is located in WorkflowManager.cs, and is responsible for creating and starting a new Navigational Workflow instance:

Collapse Copy Code

public string StartNewWorkflow(){ // create and start the navigational workflow instance WorkflowInstance instance = _workflowRuntime.CreateWorkflow(typeof(NavigationWorkflow)); instance.Start();

// execute the workflow synchronously on the current thread RunWorkflow(instance.InstanceId);

// put the workflow instance id in session for this user this.CurrentWorkflowInstanceId = instance.InstanceId;

// execute the workflow on the current thread and return the page to go to return GetPageToGoTo(instance.InstanceId);}

From here, control transfers to the Navigational Workflow instance defined in NavigationalWorkflow.cs. The InitialState is registered as the starting state of the workflow, and is the point of entry into the workflow:

The first Activity inside the InitialState Activity is of type StateInitializationActivity. The Activities within a StateInitializationActivity execute immediately upon entering a StateActivity. Double-clicking on the initializeInitialState Activity opens up the dialog below:

Page 24: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The first Activity that executes is a CodeActivity called codeInitializeInitialState, and it executes the code below:

Collapse Copy Code

private void codeInitializeInitialState_ExecuteCode(object sender, EventArgs e){ _heaviestWeight = -1; // default setting for heaviest weight}

The _heaviestWeight variable is a marker that keeps track of how far along in the Navigational Workflow a particular user got. This is used in determining whether or not the user can skip to a given State (and in essence, whether or not the user can skip to a given ASPX page). This marker will be discussed in more detail later in the section Skipping Between Pages. We will defer discussion of the remaining code in the InitialState and move on to explore the role Events play in navigation.

The Previous and Next Events: How Navigation Works

Introduction

The heart of the Navigational Workflow is the Previous and Next events. The host application raises these events via the Workflow Manager to obtain the previous and next pages to go to. Every StateActivity in the Navigational Workflow listens for the Previous and Next events. It is these events that drive transitions between different StateActivitys. Once the workflow transitions into a StateActivity, the corresponding ASPX page of the current StateActivity is queried from the web.config and passed to the host application.

Page 25: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Explanation

Let us imagine that the current State of the Navigational Workflow is the LifeStyle State:

According to the web.config, the ASPX page that maps to this State is lifestyle.aspx (that is the page the user should be on when in this State), and the weight of the Lifestyle State is 30:

Collapse Copy Code

<element stateName="LifestyleState" pageName="lifestyle.aspx" weight="30" />

The LifeStyle State listens for two events. These events are Previous and Next, and are defined in INavigationService.cs:

Collapse Copy Code

event EventHandler<ExternalDataEventArgs> Previous;event EventHandler<ExternalDataEventArgs> Next;

Let us examine how to transition to the previous page starting from the host application and work our way back to the Navigational Workflow. To navigate to the previous page, the host application makes the following call into the WorkflowManager:

Collapse Copy Code

// navigate to the previous pagestring pageToGoTo = _workflowManager.Previous();_workflowManager.ManagedRedirect(pageToGoTo);

The above code first calls the Previous method on the WorkflowManager to obtain the page to go to. The next line is a wrapper around Response.Redirect to transfer the user to the previous page. We will now explore the Previous method of the WorkflowManager:

Collapse Copy Code

public string Previous(){ /* 180 */ // prepare external data exchange arguments /* 181 */ ExternalDataEventArgs args = new ExternalDataEventArgs(this.CurrentWorkflowInstanceId);

/* 183 */ // make local service call into Navigation Workflow /* 184 */ _navigationService.OnPrevious(args);

Page 26: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

/* 186 */ // execute the workflow on the current thread and return the page to go to /* 187 */return GetPageToGoTo(args.InstanceId);}

Line 181 prepares the ExternalDataEventArgs to send to the Navigational Workflow. Line 184 raises the Previous event inside the LifestyleState in the Navigational Workflow; however, since we are using the System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService to execute our workflows, the Navigational Workflow will not receive the event until ManualWorkflowSchedulerService explicitly runs the workflow instance. Let's take a look at line 187:

Collapse Copy Code

private string GetPageToGoTo(Guid instanceId){ /* 399 */ // execute the workflow on the current asp.net thread /* 400 */ RunWorkflow(instanceId);

/* 402 */ // return where the user should go /* 403 */ return _pageToGoTo;}

Line 400 makes a call to RunWorkflow, which is where the ManualWorkflowSchedulerService gets called to execute the current Navigational Workflow instance:

Collapse Copy Code

private bool RunWorkflow(Guid instanceId){ ManualWorkflowSchedulerService scheduler = GetWorkflowSchedulerService(); return scheduler.RunWorkflow(instanceId);}

Now that control has transferred to the Navigational Workflow, let us examine how the Lifestyle State is set up to listen for the Previous event, and what happens when it receives it:

The eventLifestyleStatePrevious EventDrivenActivity contains the code that listens for the Previous event. Double-clicking eventLifestyleStatePrevious opens the following:

Page 27: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The HandleExternalEventActivity named handleLifestylePrevious is listening for the Previous event. Examining the handleLifestylePrevious properties illustrate how to set up the event listening:

After the Previous event is received, the SetStateActivity executes and moves the Navigational Workflow into the Appearance State:

Page 28: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Upon entering the Appearance State, the StateInitializationActivity named initializeAppearanceState executes. Double-clicking it opens up the designer for the Activity:

There is a single CallExternalMethodActivity. To figure out what exactly is happening, we need to investigate the properties of the CallExternalMethodActivity:

Page 29: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The CallExternalMethodActivity calls the OnPageToGoTo Local Service method, passing the PageToGoToEventArgs into it. The OnPageToGoTo method raises the PageToGoToReceived event which the WorkflowManager is listening for. Before the Local Service method executes, the CallExternalMethodActivity executes the InitializeOutgoingMessage method:

Collapse Copy Code

private void InitializeOutgoingMessage(object sender, EventArgs e){ /* 90 */ // initialize the outgoing args to send to the host application /* 91 */ _pageToGoToEventArgs = new PageToGoToEventArgs(this.WorkflowInstanceId, GetPageToGoTo()); /* 92 */ /* 93 */ // each state has a weight associated with it. keep // track of the heaviest weight (logically the /* 94 */ // furthest state in the navigation process) // so we can skip there later /* 95 */ if (_heaviestWeight < NavigationSection.Current. Elements[this.CurrentStateName].Weight) /* 96 */ { /* 97 */ _heaviestWeight = NavigationSection.Current. Elements[this.CurrentStateName].Weight; /* 98 */ }}

The GetPageToGoTo method on line 91 retrieves the corresponding page associated with this StateActivity from the web.config:

Collapse Copy Code

private string GetPageToGoTo(){ // query the page to go to from the navigation section string pageToGoTo = NavigationSection.Current. Elements[this.CurrentStateName].PageName; return pageToGoTo;}

Page 30: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

When the Local Service method OnPageToGoTo executes, the Workflow Manager is listening for it and executes the following code upon receiving the event:

Collapse Copy Code

private void _navigationService_PageToGoToReceived(object sender, PageToGoToEventArgs e){ // get the page to go to _pageToGoTo = e.PageToGoTo;}

The above code inside the Navigational Workflow executes when the RunWorkflow method is called. If we go back and take a look at the GetPageToGoTo method:

Collapse Copy Code

private string GetPageToGoTo(Guid instanceId){ /* 399 */ // execute the workflow on the current asp.net thread /* 400 */ RunWorkflow(instanceId);

/* 402 */ // return where the user should go /* 403 */ return _pageToGoTo;}

By the time line 403 executes, the _pageToGoTo variable will already have been populated with the page to go to. The host application receives this page, and then redirects accordingly.

Synchronization, Self-Healing, and the Browser Back/Forward Buttons

Browser Back/Forward Buttons

In the past, the browser's back/forward buttons have caused many issues with synchronization. The issue is that most browsers cache web pages so that when you click the browser's back/forward buttons, a cached copy of the web page is retrieved. Because the page is cached, there is no postback to the server to update the Navigational Workflow and to perform server side validation. In the past, the most simple solution was to disable the browser's back/forward buttons. This section proposes a solution to the problems presented using the browser back/forward buttons.

The first thing that must be done is caching must be disabled. With caching disabled, the browser has no choice but to postback to the server to retrieve the web page whenever the browser's back/forward buttons are clicked. There is a performance hit associated with this in that every request must be sent to the server; however, this is the only way to force a postback to the server to occur when the user clicks the browser's back/forward buttons. The code below is in the MasterPage of the host application, and disables caching across the website:

Collapse Copy Code

protected void Page_Load(object sender, EventArgs e){ // disable page caching Response.Expires = 0; Response.Cache.SetNoStore();

Page 31: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Response.AppendHeader("Pragma", "no-cache");}

The code above will make sure that the page postbacks to the server whenever the user clicks the browser's back/forward buttons. It has been tested and verified to work in both Internet Explorer 7 and Firefox. Safari 3.1, however, requires one extra step. To get the page to postback to the server when the browser's back/forward button is clicked using the Safari browser, the following JavaScript method is attached to the onunload event of the HTML body in the Master page:

Collapse Copy Code

<body onunload="javascript:safariBackForwardBrowserButtonFix();">

There is nothing fancy about the JavaScript method that is called. Its method body is empty, but nevertheless, this is what is required to force the Safari browser to postback to the server when its back/forward buttons are clicked.

But, how do we know that the page is really posting back to the server when clicking the browser's back/forward buttons? One way to test for this is to use breakpoints. However, there is also a control on every page that is called: DebuggingPane.ascx. One piece of information this control displays is the current datetime timestamp. If the timestamp changes to the current time when you click the browser's back/forward buttons, then you can be sure a postback to the server occurred.

Synchronization and Self-Healing

Synchronization ensures that the web page the user is on is the web page that they should be on. The following pages require synchronization (note that the pages in the list below are represented by StateActivitys in the Navigational Workflow, the distinction is that Error pages are not represented by StateActivitys):

1. Basics.aspx 2. Appearance.aspx 3. Lifestyle.aspx 4. Interests.aspx 5. Complete.aspx

The pages above all call the SynchronizeWorkflow method inside of their Page Load event. The SynchronizeWorkflow method is located inside the Workflow Manager class:

Collapse Copy Code

public void SynchronizeWorkflow(){ // check if there is a workflow in session if (this.CurrentWorkflowInstanceId == Guid.Empty) { // redirect to the start page ManagedRedirect(GetStartPage()); }

// the page to go to if the workflow is not synchronized string pageToGoTo = string.Empty;

try { // raise event to ask the workflow if it is synchronized

Page 32: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

IncomingSynchronizeEventArgs args = new IncomingSynchronizeEventArgs( this.CurrentWorkflowInstanceId, GetCurrentPageName()); _navigationService.OnIncomingSynchronize(args);

// execute the workflow synchronously on the current thread RunWorkflow(this.CurrentWorkflowInstanceId);

// return if the workflow is synchronized if (_isSynchronized) { return; }

// get the name of the state that the user should be in StateMachineWorkflowInstance instance = new StateMachineWorkflowInstance( _workflowRuntime, this.CurrentWorkflowInstanceId); instance.SetState(_stateToGoTo);

// get the name of the page that the user should be on pageToGoTo = Rehydrate(this.CurrentWorkflowInstanceId); } catch (Exception ex) { // could not synchronize the workflow ManagedRedirect(GetStartPage()); }

// if the page the user should be on is not // the same as the page that they currently // are on then redirect the user to the page they should be on if (!pageToGoTo.Equals(GetCurrentPageName())) { ManagedRedirect(pageToGoTo); }}

The SynchronizeWorkflow method asks the Navigational Workflow if it is in sync by raising the IncomingSynchronize event. The Navigational Workflow listens for this event, and returns its response by raising the OutgoingSynchronizeReceived event. The synchronization code checks to see if any type of URL hacking has occurred. By URL hacking, I am referring to modifications made to the World Wide Dating website URL by the user and not through the Navigational Workflow code. If the URL has been modified by the user, then the synchronization code checks to see if the URL the user is trying to navigate to is an allowable page for them to be on. If it is allowed, then the Workflow Manager will self-heal the Navigational Workflow and transition it to the proper StateActivity. If it is not, then the Workflow Manager will redirect the user back to the page they were on before they attempted to hack the URL. It is worth noting that clicking the browser's back/forward button is a way of hacking the URL; the reason being is that by clicking these buttons, events are not raised inside the Navigational Workflow that indicates it needs to transition to another State. Therefore, self-healing also occurs when using the browser back/forward buttons.

If we double-click the eventIncomingSynchronize EventDrivenActivity inside the Navigational Workflow, the below appears in the designer:

Page 33: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The HandleExternalEventActivity called handleIncomingSynchronize listens for the IncomingSynchronize event. The CallExternalEventActivity called callOnOutgoingSynchronize has the following properties:

The first thing that happens here is the InitializeOutgoingSynchronizeMessageEventArgs method executes:

Collapse Copy Code

private void InitializeOutgoingSynchronizeMessageEventArgs(object sender, EventArgs e){ NavigationElement expectedElement = NavigationSection.Current.Elements. GetElementByPageName(GetPageToGoTo()); NavigationElement currentElement =

Page 34: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

NavigationSection.Current.Elements. GetElementByPageName(_incomingSynchronizeEventArgs.CurrentPage);

// initialize the outgoing synchronize event args _outgoingSynchronizeEventArgs = new OutgoingSynchronizeEventArgs(this.WorkflowInstanceId);

// check if the workflow is synchronized by comparing the // expected page to the current page the user is on _outgoingSynchronizeEventArgs.IsSynchronized = expectedElement.PageName.Equals(currentElement.PageName);

// workflow is synchronized if (_outgoingSynchronizeEventArgs.IsSynchronized) { return; }

/* the below checks are in reference to if the user tried to manipulate the URL by hand */

// if the weight of the page the user is on is less than or equal // to the heaviest weight, then the workflow is able to "self-heal" and // transition itself to the state it should be in.the host application // will make the transition, but the StateToGoTo below tells it which is // the right state to transition to. if (currentElement.Weight <= _heaviestWeight) { _outgoingSynchronizeEventArgs.StateToGoTo = currentElement.StateName; } // otherwise the user is trying to skip to a page further // in the workflow than they can currently go, so set the // state of the workflow to be what we expect it should be else { _outgoingSynchronizeEventArgs.StateToGoTo = expectedElement.StateName; }}

The above code populates the _outgoingSynchronizeEventArgs data member with the information needed for the Workflow Manager to synchronize the Navigational Workflow. The _outgoingSynchronizeEventArgs data member maps to the OutgoingSynchronizeMessageEventArgs property. This property gets passed into the OnOutgoingSynchronize Local Service method, which when called raises the OutgoingSynchronizeReceived event that the Workflow Manager is listening for. All of this happens from the SynchronizeWorkflow method inside the WorkflowManager.

Error Pages

So far, we have established that every ASPX web page (that is part of the natural workflow, i.e.,~ not an error page) maps to a unique StateActivity within the Navigational Workflow, and that synchronization is used to ensure that we are on the correct page. Inevitably though, an error will occur sometimes in our applications, and our Navigational Workflow needs to be prepared to handle them.

When an error occurs, the host application determines what kind of error it is, and then raises the Error event inside the Navigational Workflow, and indicates to it what type of error has occurred. The Navigational Workflow then returns the error page to navigate to. The following code is an example of how the host application raises the Error event inside the Navigational Workflow and indicates to it that the type of error is "Unknown":

Page 35: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Collapse Copy Code

string pageToGoTo = _workflowManager.Error(DateSiteNavigation.ErrorType.Unknown); _workflowManager.ManagedRedirect(pageToGoTo);

The Workflow Manager executes the following code to raise the Error event inside the Navigational Workflow to obtain the error page to navigate to:

Collapse Copy Code

public string Error(ErrorType errorType){ // prepare external data exchange arguments ErrorEventArgs args = new ErrorEventArgs(this.CurrentWorkflowInstanceId, errorType);

// make local service call into Navigational Workflow _navigationService.OnError(args);

// execute the workflow on the current thread and // return the page to go to return GetPageToGoTo(args.InstanceId);}

The first concept to recognize when dealing with error pages is that an error page is always a valid page to be on regardless of what State the Navigational Workflow is in. The Error event is defined in the Local Service as:

Collapse Copy Code

event EventHandler<ErrorEventArgs> Error;

To quote Popeye The Sailor Man, "I am what I am and that's all that I am." Every page in our workflow, whether it be a navigational page or an error page, knows about itself. It does not know anything about the other pages, but it knows what its responsibilities are. That said, an error page knows it is an error page, and it understands the concept that it is always a valid page to be on in terms of navigation. Therefore, all error pages make sure to not call the synchronize workflow method.

Double-clicking the EventDrivenActivity called errorEvent inside of the Navigational Workflow opens the following in the designer:

Page 36: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The first Activity is a HandleExternalEventActivity called handleError. If we investigate its properties, we will see that it is configured to listen for the Error event, and that it binds the argument e to the Navigational Workflow property ErrorEventArgs:

After the Error event is raised, the CallExternalMethodActivity called callErrorOnPageToGoTo executes. Let's take a look at its properties:

Page 37: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Notice that the properties are almost identical to the those of the CallExternalMethodActivity discussed in the section: The Previous and Next Events: How Navigation Works. The only difference is, the MethodInvoking property calls the method InitializeErrorMessage before the Local Service method fires. This method is responsible for initializing the PageToGoToEventArgs with the name of the ASPX error page to go to:

Collapse Copy Code

private void InitializeErrorMessage(object sender, EventArgs e){ /* 109 */ // initialize the outgoing args to send to the host application /* 110 */ _pageToGoToEventArgs = new PageToGoToEventArgs( this.WorkflowInstanceId, GetErrorPageToGoTo());}

The GetErrorPageToGoTo method on line 110 gets the name of the ASPX error page to go to:

Collapse Copy Code

private string GetErrorPageToGoTo(){ // query the page to go to from the navigation section string errorName = _errorEventArgs.ErrorType.GetErrorName(); string pageToGoTo = NavigationSection.Current.Errors[errorName].PageName; return pageToGoTo;}

This method obtains the name of the error from the ErrorEventArgs. From there, it proceeds to retrieve the error page name from the web.config using NavigationSection. The web.config section that contains the error name to error page mapping looks like:

Collapse Copy Code

<errors> <error errorName="generic" pageName="genericError.aspx" /> <error errorName="unknown" pageName="unknownError.aspx" /></errors>

Page 38: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Persistence and Long Running Workflows

Most real world scenarios have a requirement that a user be able to start a new workflow, stop, and then continue at some later point in time. That later point in time could be hours, days, or even months later. We have already discussed Creating and Starting a New Navigational Workflow; now, we will cover how to rehydrate a navigational workflow from the point the user left off at. How to setup the WWF Persistence Service database tables will be covered in the Running the Code section. There is one additional table that is used to store dating profile data such as eye color, hair color, height, etc. This table is called the Profile table. It is also the table that stores the unique workflow instance ID for each user that creates a dating record. That same workflow instance ID maps to a record in the out-of-the-box WWF database table called InstanceState. The WWF table called InstanceState is where Windows Workflow Foundation stores data about workflows that have been persisted. It stores information such as the current StateActivity the workflow is in, private data members, etc.

The host application rehydrates workflows by calling the Rehydrate method of the Workflow Manager. The Rehydrate method takes the ID of the workflow instance to be rehydrated as its parameter. Below is the implementation of the Rehydrate method:

Collapse Copy Code

public string Rehydrate(Guid instanceId){ try { // prepare external data exchange arguments ExternalDataEventArgs args = new ExternalDataEventArgs(instanceId);

// make local service call into Navigation Workflow // to retrieve step user left off at _navigationService.OnRehydrated(args);

// put the workflow instance id in session this.CurrentWorkflowInstanceId = instanceId;

// execute the workflow on the current // thread and return the page to go to return GetPageToGoTo(args.InstanceId); } catch (Exception ex) { // the given workflow instance could not be rehydrated return GetStartPage(); }}

The Navigational Workflow listens for this event. Double-clicking the eventRehydrated EventDrivenActivity opens up the below in the designer:

Page 39: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

The HandleExternalEventActivity called handleRehydrated listens for the Rehydrated event. Once received, the CallExternalMethodActivity callRehydrated executes. If you look at the properties of this Activity, you will notice it is exactly the same as in the section The Previous and Next Events: How Navigation Works:

The reason it is the same has to do with what happens when you rehydrate a workflow instance in WWF: When you rehydrate a workflow instance, WWF retrieves the workflow instance from the database for the duration required to process the request made to it. Part of the information that is retrieved is the current StateActivity of the workflow. Our Navigational Workflow uses this to obtain the ASPX page from the web.config that maps to the current StateActivity. It is this page that is returned to the Workflow Manager and then to the host application. After the instance finishes processing the request, WWF will save it back into the persistence store.

Skipping Between Pages

Page 40: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Since every web page is associated with a unique StateActivity, we are actually skipping between StateActivitys in the Navigational Workflow to achieve skipping between web pages. Most real-world scenarios require a user to fill out a web form following some predefined navigational order. Once the user has gone through the predefined steps, they should (in certain circumstances) be allowed to skip back and forth between pages they have already been on to edit information. To allow this, our navigational workflow listens to the following events:

Collapse Copy Code

event EventHandler<ExternalDataEventArgs> SkipToBasics;event EventHandler<ExternalDataEventArgs> SkipToAppearance;event EventHandler<ExternalDataEventArgs> SkipToLifestyle;event EventHandler<ExternalDataEventArgs> SkipToInterests;event EventHandler<ExternalDataEventArgs> SkipToComplete;

The EventDrivenActivitys that encapsulate these events are defined at the workflow level:

Double-clicking on the EventDrivenActivity eventSkipToLifestyle opens up the following in the designer:

Page 41: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Once the HandlExternalEventActivity called handleSkipToLifestyle receives the SkipToLifestyle event, control transfers to the IfElseActivity. The IfElseBranchActivity on the left uses a code condition to check and see if skipping to the LifestyleState is a valid navigational move. This is where the _heaviestWeight variable comes into play. Each StateActivity has a weight that is associated with it, and as the navigational workflow transitions to States with heavier weights, it stores that weight in the _heaviestWeight variable.

According to the web.config, the Lifestyle State has a weight of 30:

Collapse Copy Code

<element stateName="LifestyleState" pageName="lifestyle.aspx" weight="30" />

Skipping to the Lifestyle state is valid if 30 is less than or equal to the heaviest known weight. The CodeCondition method that determines if skipping to the LifeStyle State is valid is defined as:

Collapse Copy Code

private void CanSkipToLifestyleState(object sender, ConditionalEventArgs e){ int lifestyleWeight = NavigationSection.Current.Elements[LifestyleState.Name].Weight;

Page 42: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

e.Result = lifestyleWeight <= _heaviestWeight;}

If the Code Condition evaluates to true, then the Navigational Workflow transitions to the Lifestyle State; otherwise, the IfElseBranchActivity on the right executes. Examining the properties of the CallExternalMethodActivity callSkipToLifestyleOnPageToGoTo reveals that the Navigational Workflow is preparing to return an error page as the page to go to. This illustrates an example of how to redirect the host application to an error page from the Navigational Workflow. The example in the section Error Pages illustrated how to redirect to an error page from the host application. Below are the properties of callSkipToLifestyleOnPageToGoTo:

Investigating the InitializeCannotSkipToStateErrorMessage reveals which error page the Navigational Workflow is going to return:

Collapse Copy Code

private void InitializeCannotSkipToStateErrorMessage(object sender, EventArgs e){ // get the error page to go to string pageToGoTo = NavigationSection.Current. Errors[ErrorType.Generic.GetErrorName()].PageName;

// initialize the outgoing args to send to the host application _pageToGoToEventArgs = new PageToGoToEventArgs(this.WorkflowInstanceId, pageToGoTo);}

The GenericError is defined in the web.config as:

Collapse Copy Code

<error errorName="generic" pageName="genericError.aspx" />

What this means is that the user will get redirected to genericError.aspx whenever they attempt to skip to a web page they have not yet been on. The "natural flow" of the Navigational Workflow is to transition to and from StateActivitys using the Previous and Next events. The skip events are used as an example to simulate one type of real-world scenario.

Page 43: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Running the Code

World Wide Dating requires Microsoft SQL Server 2005 (any edition). The required SQL scripts are in a folder called "database setup procedure" inside the DateSite project. The setup procedure is as follows:

1. Create a database called Dating 2. Run Profile_Schema.sql 3. Run SqlPersistenceService_Schema.sql (WWF script) 4. Run SqlPersistenceService_Logic.sql (WWF script)

Alternatively, the composite.sql file contains all the necessary SQL scripts bunched into one file. After the database has been setup, open up the DateSite Solution and run the DateSite project.

Note About Different SQL Server 2005 Versions

Many people have posted messages regarding the following error:

Collapse Copy Code

navigationService = _workflowRuntime.GetService() as NavigationService

System.NullReferenceException: Object reference not set to an instance of an object

The most common cause of this error is an incorrect connection string. World Wide Dating was coded using SQL Server 2005 Developer Edition, and assumes the Dating database is located on the server named localhost. If you are getting this error, you may need to modify your database connection string to point to the proper database server.

Common Interview Questions in WWF

Page 44: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Windows Workflow Foundation (WWF) Interview Questions

Introduction What is Windows Workflow Foundation? What is a Workflow? What are different types of Workflow in Windows Workflow foundation? When should we use a sequential workflow and when should we use state machines? How do we create workflows using designer? How do we specify conditions in Work flow? How do you handle exceptions in workflow? What is the use of XOML files? How can we pass parameters to workflow?

 

Introduction

In this FAQ we will quickly run through and get a feel of how WWF (Windows Workflow Foundation) will help you in making custom work flows in your project.

Happy job hunting......

 

What is Windows Workflow Foundation?

WWF is a programming model for building workflow-enabled applications on windows. System. Workflow namespace has all the necessary modules to develop any type of workflow.

 

What is a Workflow?

A Workflow is a set of activities, which is stored as model and they depict a process. Below figure depicts clearly the difference between Workflow and Activity. Every task is an activity and group of activity depicts a complete workflow. Workflow is run by the Workflow runtime engine.

Page 45: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Figure 1: - Work Flow Foundation Architecture

Workflow model can be written in pure .NET code, pure XAML or Mix of XAML and .NET Code. A workflow model is compiled and can execute under windows, ASP.NET, Web services or windows services application. 

 

What are different types of Workflow in Windows Workflow foundation?

There are two basics type of workflow Sequential Workflow and State machines workflow.A sequential workflow has clear start and finish boundaries. Workflow controls execution in Sequential workflow. In sequential execution, one task is executed after other. Sequential workflow is more rigid in format and execution path has a deterministic nature.A State machine workflow is more dynamic in nature. Workflow has states and the state waits for events to help it move to next state. In State machine execution path is undeterministic nature.Below figure shows visual conceptualization of fundamentals. You can see in Sequential workflow the execution path is very determent. Shiv performs the entire task sequentially and these tasks are very determent. Now have a look at the second workflow. Every state goes to other state when it receives some external events. For instance when Shiv is seeing star trek there is an event of flashing news which triggers him to see the flashing new.

Page 46: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Figure 2: - Sequential and State machine workflow

 

When should we use a sequential workflow and when should we use state machines?

If the workflow is very rigid then you go for sequential workflow and if the workflow is dynamic then go for State machine workflow. For instance you have placed an order and the order will not pass until your supervisor approves is a rigid flow. Because your order has to be approved by, a supervisor or else it will not be approved. But what if your order moves from one place to other place. For instance, it moves from approval to waiting and then clarification a state machine workflow model is more appropriate.Below is a simple code snippet which shows practically how to use sequential workflow. Let try to understand step by step as marked in the figure:-1 - First you need to select System. Workflow namespace.2, 3, and 4 - In these three steps we created code object and linked them with activity.5, 6, 7, and 8 - We start the workflow and create workflow instance object to run the sequential workflow. You can see the output in 8. Depending on how you add the activity in section 3, it executes sequentially. Because we have added codeactivity1, first it executes the first activity first. The sequence on how you add the activity to the activities collection the activities are run.

Page 47: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Figure: - 3 Code snippet for workflow

Note: - The above code snippet was developed with out using designer. The whole point was to make you understand what happens behind the scenes. In real projects you will be dependent on designer rather than coding manually. You can find the above code in SimpleWorkFlowSampleManual folder.

 

How do we create workflows using designer?

As said previously it is very easy to design workflows using designer. So we will answer this question by actually doing a small sample. Below is the code snippet and image snapshot which shows how we can use the designer to create workflows. So lets understand all the below numbered snapshot.

1. First select a sequential workflow project. In this case, we have selected Sequential workflow console application to keep the sample simple.

2. When you are done with creating the project you will see the solution explorer as shown in the second snapshot. There are two files one the WorkFlow1.cs and the other Workflow1.designer.cs.If you click on the

Page 48: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

WorkFlow1.cs you will get a designer pane as shown in snapshot 3. If you double click on Workflow1.designer.cs, you will get behind code as shown in snapshot 4.

3. So let us drag drop a code activity on the workflow designer and associate this activity with a method called as MyActivity1. This association is done by entering the method name in Execute Code property. In MyActivity1, we have just displayed in the console that this is my first activity. Again, we have added one more code activity, which points to MyActivity2. If you see the designer pane we have sequenced code1 first and code2 next. So in short, code1 will execute first and the code2. This is clear from the output displayed below.

4. This is the behind code of the workflow.

Figure 4 Sequential workflow using designer

Page 49: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

 

How do we specify conditions in Work flow?

Yes, you can define conditions in workflow by using conditionedActivitygroup. Below is the numbered snapshot, which shows how to use conditionedActivitygroup.

1. You can see in this snapshot we have defined a conditionedActivitygroup with two conditions. The two boxes inside the group define two conditions.

2. You can select one of the condition box and define the condition using the When Conditions property. If this condition is true you need to specify in the execute code which method to execute. For instance in the current snapshot we have said that old1 method should execute if age > 21. The same procedure we need to follow for the second condition box. In the second condition box we have specified to execute young1 method if age < 21. Currently the second condition is not visible in the below snapshot.

3. Workflow editor also provides a cool interface called as Rule Condition Editor, which can be used to specify conditions. Age is a public property in the behind code. You can also get the Age in the intelligence of rule condition editor.

4. Both the condition will execute inside the condition activity group. We need to also specify when this conditionactivitygroup should exit. Therefore, we have made a function called as exit. If the user inputs age as -1 it will exit from the loop or else it will take inputs from user and continue evaluating depending on the two conditions.

Page 50: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Figure 5:- Sequential workflow with conditions

 

How do you handle exceptions in workflow?

Exception handling in Workflow is somewhat different than how we do in normal .NET application. Below is the numbered snapshot of how we can handle exceptions in Workflow.

1. We have small tab, which says view exceptions. If you click on view exception, you will be redirected to a workflow design only for exception as shown in numbered snapshot 2.

2. This is the workflow which will execute incase we have exceptions. We have put a code activity, which points to a method called as raise Exception. Incase of exception in the workflow this path will be followed.

Page 51: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

Figure 6:- Workflow with exception handling

 

What is the use of XOML files?

Twist: - How can we serialize workflows?

Windows Workflow Foundation gives developers a declarative way to create workflows by using XAML. See WPF chapter for more details about XAML. These markup files are Stored with XOML (Extensible Object Markup Language) extension. In the below snapshot you can see Workflow1.xoml file created by designer. Markup file can also have code behind. The whole concept of having code behind for XOML file is to separate the presentation from logic files.In the below code snapshot we have made a simple XOML sample. Below is the explanation number wise:

1. In order to create a XOML file you need to add sequential workflow with separation. Which means that XOML file will be created with a behind code.

2. Currently we have two activity code3 and code1. Below is the XOML file contents:

<?Mapping XmlNamespace="ComponentModel"

Page 52: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

ClrNamespace="System.Workflow.ComponentModel" Assembly="System.Workflow.ComponentModel" ?>

<?Mapping XmlNamespace="Compiler" ClrNamespace="System.Workflow.ComponentModel.Compiler" Assembly="System.Workflow.ComponentModel" ?>

<?Mapping XmlNamespace="Activities" ClrNamespace="System.Workflow.Activities" Assembly="System.Workflow.Activities" ?>

<?Mapping XmlNamespace="RuleConditions" ClrNamespace="System.Workflow.Activities.Rules" Assembly="System.Workflow.Activities" ?>

<SequentialWorkflow x:Class="WorkflowSeq.Workflow1" x:CompileWith="Workflow1.xoml.cs" ID="Workflow1" xmlns:x="Definition" xmlns="Activities">

<Code ExecuteCode="Mycode3" ID="code3" /><Code ExecuteCode="Mycode1" ID="code1" /></SequentialWorkflow>

 

See the above snippet of the XOML file. You can see how the behind code is linked using the Compile With attribute. Code forms the element of the Sequential Workflow tag. One of the best thing with Markup is we can change the sequence just by changing the XOML file we do not need to compile the whole application again.

Figure 7:- XOML in action

In the above snapshot, one of the things to now is 3, 4, and 5 numbered sections. These sections are not linked with the sample. But just to make you aware you can

Page 53: Preface - Home - Srujana-Shiva.net€¦  · Web viewYou may have WCF and WPF ... This article is a case-study on the internals of a Navigational Workflow engine for a fictional dating

create serialize any workflow and deserialize them again using the text writer object.

 

How can we pass parameters to workflow?

When you call the start workflow function, you can pass as name / value pairs using the dictionary object.

Figure 8:- Passing value to workflow