Requirement
- Visual Studio 2005 Version 8.0.50727.42
- .Net Framework 3.0 or above
-
Visual Studio extensions for workflow (file: Visual Studio 2005 Extensions for Windows Workflow Foundation (EN).exe): http://www.microsoft.com/downloads/details.aspx?familyid=5D61409E-1FA3-48CF-8023-E8F38E709BA6&displaylang=en
Workflow Types
- Sequential workflow
- Good for business process
- Not so good for user interaction
- State machinen workflow
- Good for lots of user interactions
- Rule driven workflow, based on sequential workflow
- More complicate and costly
Two types of activities
- Composite activities
- Contains other activities, e.g. sequential acitivities
- Basic activities
- Does the actual work
System.Workflow.Runtime.WorkFlowRuntime object
- Properties
- IsStarted
- Methods
- AddService
- CreateWorkflow
- StartRuntime
- StopRuntime
- Events
- Started
- Stopped
- WorkflowCompleted
- WorkflowIdled
- WorkflowTerminated
WorkflowInstance object
- Properties
- InstanceId
- WorkflowRuntime
- Methods
- ApplyWorkflowChanges
- GetWorkflowDefinition
- Resume
- Start
- Suspend
- Terminate:
instance.Terminate("User cancellation.");
- Events
- Status:
workflowInstance.GetWorkflowDefinition().ExecutionStatus.ToString();
Activity object
- Properties
- Description
- Enabled
- ExecutionResult
- ExecutionStatus
- ActivityExecutionStatus
- Name
- Parent
- WorkflowInstanceId
- Methods (they are all protected virtual methods)
- Cancel
- Clone
- Execute
- GetActivityByName
- Load
- RaiseEvent
- RaiseGenericEvent<T>
- Save
- Events
ActivityExecutionContext class
- Created by workflow runtime
- Provide info about workflow instance
- Initialization
- Timers
- General execution flow
Sequence Activity Object
- Is a composite activity
Code Activity
Throw/FaultHandler Activities
- Each FaultHandler is designed to handle one, and only one, exception type.
Suspend Activity
Terminate Activity
- Difference from workflow termination by unhandled exception
- WorkflowTerminatedEventArgs.Exception is of the type System.Workflow. ComponentModel.WorkflowTerminatedException
Workflow interprocess communication
- WF uses an abstraction layer to buffer workflow from host
- Local communication service
- Need to add ExternalDataService to workflow runtime?
- Create a workflow data communicaiton interface
- Annotate with [ExternalDataExchange] (marker interface for local communication service)
public interface IMVDataService
{
[ExternalDataExchange]
void MVDataUpdate (DataSet mvData);
} - Create a workflow data event argument class
[Serializable]
public class MVDataAvailableArgs : ExternalDataEventArgs
{
public MVDataAvailableArgs(Guid instanceId)
: base(instanceId)
{
}
}
Pluggable services
- Additonal software functions that your workflow can use to complete their tasks
- Some are optional and some are required
- They are pluggable
- Base workflow services
- WorkflowPersistenceService
- WorkflowQueuingService
- WorkflowRuntimeService
- WorkflowSchedulerService
- DefaultWorkflowSchedulerService
- ManualWorkflowSchedulerService
- WorkflowSubscriptionService
- WorkflowTransactionService
- TrackingService
- SqlTrackingService
- Can use Workflowmonitor to query
- Tracking specification objects
- Tracking retrieval objects
- Example
- SqlTrackingQuery
- Activity events
- ActivityTrackingPoint
- ActivityTrackingLocation
- Workflow events
- User events
- Example
- Tracking records are decorated with annotations
- Tracking level determined in tracking profile
- XML doc
- ConsoleTrackingService
- SimpleFileTrackingService
- SqlTrackingService
Pass Dictionary object as a parameter to workflow instance
- In the activity class
public sealed partial class Workflow1: SequentialWorkflowActivity
{
private Int32 _delay = 10;public Workflow1()
{
InitializeComponent();
}// Receives value from parameter
public Int32 Delay
{
get { return _delay; }
set
{
if (value < 0 || value > 120)
{
value = 10;
}
if (ExecutionStatus == ActivityExecutionStatus.Initialized)
{
_delay = value;
delayActivity1.TimeoutDuration = new TimeSpan(0, 0, _delay);
}
}
}private void PreDelayMessage(object sender, EventArgs e)
{
MessageBox.Show("Pre-delay code is being executed.");
}private void PostDelayMessage(object sender, EventArgs e)
{
MessageBox.Show("Post-delay code is being executed.");
}
} - In the main program
class Program
{
private static AutoResetEvent _waitHandle = new AutoResetEvent(false);
static void Main(string[] args)
{
WorkflowRuntime wfr = WorkflowFactory.GetWorkflowRuntime();
wfr.WorkflowIdled +=
new EventHandler(wfr_WorkflowIdled);
wfr.WorkflowCompleted +=
new EventHandler(wfr_WorkflowCompleted);
wfr.WorkflowTerminated +=
new EventHandler(wfr_WorkflowTerminated);Int32 delay = 0;
string val = args.Length > 0 ? args[0] : "10";
if (!Int32.TryParse(val, out delay))
{
Console.WriteLine("You must pass in an integer value.");
return;
}// Constructs a Dictionary object as workflow instance parameter
Dictionaryprms = new Dictionary ();
prms.Add("Delay", delay);Console.WriteLine("Waiting for workflow completion ({0} seconds).", val);WorkflowInstance wfi =
// Pass the Dictionary object as parameter
wfr.CreateWorkflow(typeof(LongRunningWorkflow.Workflow1), prms);
wfi.Start();
_waitHandle.WaitOne();
Console.WriteLine("Done.");
}
static void wfr_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine("Workflow terminated.");
_waitHandle.Set();
}
static void wfr_WorkflowIdled(object sender, WorkflowEventArgs e)
{
Console.WriteLine("Workflow idled.");
}static void wfr_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
Console.WriteLine("Workflow completed.");
_waitHandle.Set();
}
}