TO DO
This example performs a very simple logic: it reads user-specific flags from a configuration file to determine whether the user is required to log-in (ieaLogin activity) and what privileges the user should have(ieaPrivileges). The overall workflow is called Workflow1 and is shown below:
The following explains the workflow structure:
The first activity is ieaLogin activity
of type System.Workflow.Activities.IfElseActivity.
IfElseActivity activity is similar to an
If-else-if statement; it conditionally runs two or
more activities (iebLogin and
iebNoLogin) of type IfElseBranchActivity.
Each branch of type IfElseBranchActivity must have a
condition to determine whether the branch should execute or note. The final
branch is not required to have a condition, in which case it always evaluates to
true. The following shows the
Properties window for the first IfElseBranchActivity
activity. Note how the Condition property is set to
IsLoginRequired:
private void IsLoginRequired(object sender,
ConditionalEventArgs e)
{
Trace.WriteLine("IsLoginRequired");
e.Result = _bLogin;
// if e.Result is true, iebLogin branch will execute.
}
iegLogin branch will execute, but what will it execute? In this case, a CodeActivity activity is configured via its properties to execute the Login method:
private void Login(object sender, EventArgs e)
{
Trace.WriteLine("Login");
// Perform
login operations here
...
}
Note that code executed by a CodeActivity activity is executed in a synchronous manner. CodeActivity does not yield its thread until the thread is finished. Therefore, the code is expected to be performed and should not block on some external resource. Typical use of CodeActivity is to examine workflow instance state and change local variables and messages.
The same exact approach is used for the ieaPrivileges activity and its branches (iebGuest, iebUser, iebAdmin).
The following code extracted from the designer-generated code shows the actual types used for each workflow item:
private IfElseActivity
ieaLogin;
private IfElseBranchActivity iefNoLogin;
private IfElseBranchActivity iebLogin;
private CodeActivity
caDoNotLogin;
private CodeActivity caLogin;
private IfElseActivity ieaPrivileges;
private IfElseBranchActivity iebAdmin;
private IfElseBranchActivity iebUser;
private IfElseBranchActivity iebGuest;
private CodeActivity caAdmin;
private CodeActivity caUser;
private CodeActivity caGuest;
Full-code, except for the designer-generated code, is shown below:
// Code for work flow
Workflow1. Designer-generated code is not included
public sealed partial class Workflow1: SequentialWorkflowActivity
{
#region Data members
private bool _bLogin = false;
private string _Privilege = String.Empty;
#endregion
public Workflow1()
{
InitializeComponent();
// Invokes designer-generated code (not shown)
InitFlags();
}
#region Helpers
private void InitFlags()
{
// Initialize
flags. These flags are used to determine which activities are executed
_bLogin =
Convert.ToBoolean(ConfigurationManager.AppSettings["Login"]);
_Privilege =
Convert.ToString(ConfigurationManager.AppSettings["Privilege"]);
}
#endregion
/// This region of code uses an
ifElseActivity to determine if a user need to log
/// in or not. Note that for the iebLogin activity, the
Condition property should
/// be set on the left-most branch (iebLogin). If you set if
on any other branch,
/// you will get the following error:
/// error WF278: Activity 'iebLogin' validation failed:
Property 'Condition' is not set
#region ieaLogin
// Determine if user needs to log in
private void IsLoginRequired(object sender,
ConditionalEventArgs e)
{
Trace.WriteLine("IsLoginRequired");
e.Result = _bLogin;
// User should log in
}
private void Login(object sender, EventArgs e)
{
Trace.WriteLine("Login");
// Perform
login operations
}
private void DoNotLogin(object sender, EventArgs e)
{
Trace.WriteLine("DoNotLogin");
// Set flag to
indicate user not required to login
}
#endregion
/// This region of code uses an
ifElseActivity to determine user permissions.
/// Note that there are three branches and the Condition
property needs to be
/// set on each branch (last branch can leave its Condition
property not set
/// and hence acts as the 'else' of an 'if' statement).
/// Just like an if-elseif-else statement, runtime starts by
evaluating the
/// ieaPrivileges activity from left-to-right starting with
IsGuest, then
/// IsUser, and finally IsAdmin (look at output traces)
#region ieaPrivileges
private void IsGuest(object sender,
ConditionalEventArgs e)
{
Trace.WriteLine("IsGuest");
// Is logged
under a guest
e.Result = (_Privilege ==
"guest") ? true : false;
}
private void IsUser(object sender, ConditionalEventArgs e)
{
Trace.WriteLine("IsUser");
// Is logged
under a user
e.Result = (_Privilege ==
"user") ? true : false;
}
private void caGuest_ExecuteCode(object sender, EventArgs e)
{
Trace.WriteLine("caGuest_ExecuteCode");
}
private void caUser_ExecuteCode(object sender, EventArgs e)
{
Trace.WriteLine("caUser_ExecuteCode");
}
private void caAdmin_ExecuteCode(object sender, EventArgs e)
{
Trace.WriteLine("caAdmin_ExecuteCode");
}
#endregion
}
// Main program code to initialize
and start the workflow
class Program
{
static void Main(string[] args)
{
using(WorkflowRuntime workflowRuntime
= new WorkflowRuntime())
{
// Setup evnet to capture workflow events
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender,
WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};
workflowRuntime.WorkflowTerminated += delegate(object sender,
WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
// Create and start the workflow. BasicSequentialWorkflow.Workflow1 is the
actual workflow implementation
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(BasicSequentialWorkflow.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
}
}