Introduction
This
is the third article in introductory series of articles on 'Windows Workflow
Foundation'. In the first article we took at quick tour of Windows Workflow Foundation and also developed
a rudimentary flight booking system which was based on 'sequential workflow'.
Later on, we explored 'state-machine workflow' in the second article
and developed a purchase
ordering system. Now we will focus on XAML and
learn how we can use it to design workflows in Windows Workflow Foundation.
Hello
XAML!
Extensible
Application Markup Language or XAML (pronounced zammel) is a new declarative language that is used in
Windows Framework and Windows Presentation Foundation. Introduced with .NET
Framework 3.0, XAML is harbinger of declarative (in contrast with
imperative using coding) programming model. In Workflow Foundation, workflows
can be created using code as well as XAML. Even fully XAML-based solutions are
possible with no code at all! This not only gives flexibility of
no-compilation-needed to applications, it also opens up a window of possibility
for entirely non-technical persons (like business analysts) to design
workflows. (Though Workflow Foundation is targeted for programmers, experiments
are underway around the globe for making it feasible for business analysts to model
processes in it).
XAML
and Workflow Foundation
One
can design workflow in three possible ways using Workflow Foundation; purely
code based, partially code/XAML based, and totally XAML based. Partially
code/XAML based workflows are combination of code and XAML. For instance, a
typical scenario would be: a panoramic view of application is taken and
workflow is defined using XAML, and later on, technical nitty-gritty is added
by developer(s) for each workflow activity in code. These solutions need
compilation. Purely XAML based solutions have workflow as well as all
conditions/rules specified in XAML and can be hosted without compilation,
though 'XAML Activation' would be needed to make them work.
What
we are going to cover in this article
We
will develop the world's simplest sequential workflow using XAML, add few rules
'declaratively' i.e. in XAML and then insert some code of displaying in
console. We will learn a declarative programming model, play with XAML and see
how integration of XAML and code can work!
Let's
start the show
To
all alpha blue geeks, I salute their patience for bearing all my theoretical
musings till now, and invite them into venturing some real exciting practical work.
Click on 'Microsoft Visual Studio 2005' in your Start menu, select 'Create New
Project' and select 'Sequential Workflow Console Application'.
By
default, Workflow Project includes code based workflow file, now since we would
rather want to play with XAML, we will delete the file. Right-click project in
'Solutions Explorer', select 'Add New Item' and select 'Sequential Workflow
with Code Separation' file. 'Code Separation' is an indicator that we are doing
'something exciting' (read: XAML) separate than crude code here.
That
done, click on 'Add' and you would see standard empty workflow designer window.
Hang here for a moment and let's explore what files are included in our pet
project. In the 'Solution Explorer' window, there is MyWorkflow.xoml, this is the
file that contains our XAML for workflow. Since workflow is empty right now, if
you open-up the file, it would only have header node. [You can view XAML by
right-clicking the file and selecting 'view in browser' or alternatively, go
into the project folder, selecting MyWorkflow.xoml file and opening in your
favorite XML editor.]. Here is how MyWorkflow.xoml should be look like
currently.
<SequentialWorkflowActivity x:Class="FirstXAMLWFApplication.MyWorkflow 1"
Name="MyWorkflow 1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</SequentialWorkflowActivity>
Let's
do a quick look at it with a magnifying glass. The root element is the 'Sequential
Workflow Activity'; as it should be, since we are developing a sequential
workflow application.
The other option is StateMachineWorkflowActivity. The
element has two important attributes; Class and Name, where 'Class' specifies
fully classified name of our workflow class, 'Name' is simply our workflow's
'name' property value.
To
quench our thirst for doing-something-exciting, let's add a While
activity in our
workflow. A While
activity is part of Microsoft's provided 'Base Activity
Library' which contains numerous activities that are used in a variety of
workflows, irrespective of which business domain they belong to. A few activities in the library
are: Code
, IfElse
, Delay
, WebServiceInput
, Replicator
etc.
The While
activity is
one of the simplest and mostly used. Almost every workflow has task(s) that
are needed to run in iteration; hence While
activity, where unless a particular
condition is fulfilled, the loop continues to run a specific activity.
We
can always add the While
activity by doing a drag-drop in the Workflow designer window, but
let's play with the cool and crude XAML first.
Open up MyWorkFlow.xoml and add the
following code (shown in bold).
<SequentialWorkflowActivity
x:Class="FirstXAMLWFApplication. MyWorkflow" Name="MyWorkflow "
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<WhileActivity x:Name="whileActivity1">
</WhileActivity>
</SequentialWorkflowActivity>
Save
the file and switch back to VS.NET IDE and open up workflow. It will look like:
Cool
right!? But can you see that red exclamation sign? It is denoting the fact that
we haven't specified any condition for the loop to terminate. Let's go into the
code and add a protected variable in the workflow class. Code excerpt:
namespace FirstXAMLWFApplication
{
public partial class MyWorkflow : SequentialWorkflowActivity
{
public Int32 counter;
}
}
Go
back to the designer window and select 'Declarative Rule Condition' in the 'Condition'
property of the While
activity, then click on 'Ellipse' of 'Condition Name'. The following
dialog should display.
Click
on 'Add' to go to the 'Rule Condition Editor' and add the following condition.
We
have added a simple condition here which will make the While
loop continue until
counter
reaches 10, where it will terminate. This is probably a good time to go
back to our XAML file and see how this declarative condition got added in it.
<SequentialWorkflowActivity x:Class="FirstXAMLWFApplication.MyWorkflow"
x:Name="MyWorkflow"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<WhileActivity x:Name="whileActivity1">
<WhileActivity.Condition>
<RuleConditionReference ConditionName="Condition1" />
</WhileActivity.Condition>
</WhileActivity>
</SequentialWorkflowActivity>
"Well,
I can see the condition property is set as Condition1
which was the name of our
recently added condition, but where is the actual condition statement?" Good
question! There is a separate file in a project named as MyWorkflow.rules, all
rules are kept in this file. For brevity's sake, I am not adding an excerpt
from the file (though you can always download it along with the attached code at the top of the article
to have a detailed look into it). For now, let it suffice that our declarative rule statement is present in the .rules file, while the condition
name goes into XAML. This again shows us the power of using XAML for designing workflows,
as I can add a million rules in my project and relate it with some particular
activity by adding a single line in XAML! And can even later edit/replace it by
simply changing the name of the condition and that's it!
That's
good enough for making the while activity execute, now let's add an activity within
this one. You can think of it as the loop's body. Here we will add an IfElse
activity and then a Code
activity for each IfElse
branch within the While
activity.
This time we will use power of VS IDE and simply drag-drop activities within
workflow designer. The final shape of workflow after the addition of these new
activities would be like:
As
we can see, the IfElse
activity has two branches. One is executed when the If
condition is true and the other when the else
condition is true. We will assign proper
conditions to each of branch, but for now let's have a look at our XAML file to
see how this change in workflow got translated in it.
<SequentialWorkflowActivity x:Class="FirstXAMLWFApplication.MyWorkflow"
x:Name="MyWorkflow" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<WhileActivity x:Name="whileActivity1">
<WhileActivity.Condition>
<RuleConditionReference ConditionName="Condition1"/>
</WhileActivity.Condition>
<IfElseActivity x:Name="ifElseActivity1">
<IfElseBranchActivity x:Name="ifElseBranchActivity1">
<CodeActivity x:Name="codeActivity1"
ExecuteCode="codeActivity1_ExecuteCode" />
</IfElseBranchActivity>
<IfElseBranchActivity x:Name="ifElseBranchActivity2">
<CodeActivity x:Name="codeActivity2"
ExecuteCode="codeActivity2_ExecuteCode" />
</IfElseBranchActivity>
</IfElseActivity>
</WhileActivity>
</SequentialWorkflowActivity>
Simple and structured? You bet it is! Bold statements shows our new IfElse
and Code
activities. Now we add simple conditions in each branch of the IfElse
activity. For keeping it simple, we will simply check if the counter is even or
odd, and on the basis of this condition check, send each control to each branch. We
will add these two rules and assign them to each branch using the same mechanism
(from the Properties window -> Select Condition -> Rule Condition Editor) as
we did for While
activity. Our condition for each branch will be:
this.counter
% 2 == 0
this.counter
% 2 != 0
Finally,
our 'Select Condition' looks like:
Hey!
Didn't I say we will write some code? Yes I did, and it is time to do
so. Select 'CodeActivity1', click on 'Generate Handlers' in the 'Properties' window
and delve into its handler code. Add the following code in it. We have simply
displayed on the console announcing this is an even number and incremented our
counter variable.
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello! " + Convert.ToString(counter) +
" is an even number!");
counter++;
}
Similarly, add following code for 'CodeActivity2'.
private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello! " + Convert.ToString(counter) +
" is an odd number!");
counter++;
}
Yey!
That's it. We have our complete workflow. Let's go through what we did.
- We
added a while activity using XAML.
- We
added a condition in the while activity 'declaratively'. The condition simply
checks whether the
counter
field is less than 10 - We
then drag-dropped
IfElse
and CodeActivity
within While
activity. - Proper
conditions were added in each branch of the
IfElse
activity to check whether
its an even / odd number - Code
was added in the
Code
activity handler for display at console and
incrementing the counter
field.
Workflow
runtime needs a host to run workflows. Our host will be a simple console
application. Our project contains Progam.cs, here our workflow runtime will
actually get started. A workflow instance is created, executed and then runtime gets
closed. There is not much science here; pretty simple code generated by VS IDE
for us:
static void Main(string[] args)
{
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
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();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(
typeof(FirstXAMLWFApplication.MyWorkflow));
instance.Start();
waitHandle.WaitOne();
Console.ReadKey();
}
}
A new
runtime object is created. Two event handlers are provided for 'Completed' and
'Terminated' statuses for Workflow. Then 'Create Workflow' is called to get an
instance of our workflow and 'Start' is called to launch it. The runtime engine
will execute our workflow asynchronously, therefore, we need to block our thread
on the AutoResetEvent
object and wait for workflow to complete (otherwise even
before we could see what's written on our console window, it will close and
the program will exit!). Now, using AutoResetEvent
means the thread will be blocked
until it is 'set' in complete event handler.
That
is it, buddies. Click on 'Run' and watch the show. Well our output will not
have much for our aesthetic senses, but it should give us good idea about what
XAML is. Why and how to use it with Workflow Foundation.
Our
output window looks like:
What
more we can do with XAML in Workflow Foundation?
A
lot! We can even design fully XAML-based workflows and we won't even need to
compile them. That is, one can just design a workflow using XAML (any tool
other than Visual Studio can also be used, after all it's all about
creating/altering an XML-like document) and deploy it to run. 'XAML Activation' is
used in place of compilation to launch the workflow. This was beyond scope of this
article and we opted or a mid-way approach, of using both XAML and code
(declarative and imperative programming model) as this is how workflows are
vastly designed and implemented.
Where
to find more
My
favorite books/links remain same as was specified in my previous articles.