What You’ll Learn in This Hour:
Creating a workflow with basic activities and rules
Adding parameters to a workflow
Creating a XAML + code workflow
Creating XAML-only workflows
In this hour, you will create a sequential workflow using selected Base Activity Library (BAL) activities. You add both code conditions and declarative rules and run and debug the workflow. Then you re-create the workflow as a code-separated workflow, edit the XAML, and run it from the console host as an XML text reader.
As this hour’s name implies, its intent is to give you a basic understanding of many of WF’s features.
The basic concept of developing a workflow is covered in this section. This will be expanded on in later hours when, among other items, you learn more about advanced host-workflow data exchange options and workflow events. The goal here is to get you up to speed with the WF basics.
There are six workflow project types in Visual Studio. The most basic, the Empty Workflow Project, references the workflow DLLs, adds some namespace declarations, and enables the workflow debugger. All other workflow projects build on this project. There are two sequential workflow projects. The Sequential Workflow Console Host project creates a console host for the workflow. Generally, you will use this project type when creating a simple project or for testing purposes. The Sequential Workflow Library creates a workflow but no host. Separating the workflows from the host is usually a good idea because it makes it easier to reuse workflows across multiple hosts. There are two state machine workflow projects as well that follow the sequential workflow project pattern. Finally, there is a workflow activity project type that is used to create custom activities.
If you have problems debugging workflows, it may be because your project was created from a non-workflow project that manually referenced the WF assemblies.
If you’re using Visual Studio 2005, expand the Project Types and select Workflow instead of selecting C# first in step 2.
Use the following steps to create a Sequential Workflow Console Application project now:
1. Start Visual Studio 2008. Select File, New, Project.
2. Expand the Visual C# project templates and select Workflow.
3. Select the Sequential Workflow Console Application project template.
4. Enter FirstWorkflowProject
as the Name.
5. Enter or browse to C:SamsWf24hrsHoursHour02ASpinAroundWF
for the Location.
Your screen should now match Figure 2.1.
6. Select OK.
In the next subsection you add activities to the workflow. In the immediately following section, you will learn to pause the host application so that you can see results printed to the console by the workflow.
The workflow is a class, or two partial classes. One class holds the activities. The other holds the code-beside logic for these controls. By default, one file with a .cs
extension (Workflow1.cs
) contains the code-beside logic and another, named .designer.cs
, holds the activities on the workflow. This structure is the same as for a form in a Windows Forms application. The activities may also be stored in XML, as will be discussed later in the “Examining the Project Files” section.
1. Right-click Workflow1.cs
in the Solution Explorer and select View Code to open the workflow in code view. You will see some namespace declarations and a Workflow1
class with a constructor. The constructor is the method with the same name as the class. Again, this is very similar to what you would see in the code-behind section of a form in a Windows Forms application.
2. Double-click Workflow1.cs
in the Solution Explorer to open the workflow in design mode (see Figure 2.2). This is the designer.cs
file being opened by the workflow designer. I will refer to this as design mode throughout the book. The combination of the two—the .cs
and the designer.cs
form—represent the entire workflow class.
3. Select View, Toolbox and click the + to the left of the Windows Workflow v3.0 section to bring up the BAL activities (they are also visible in the left portion of Figure 2.2) that you will drag and drop onto the workflow and then set their properties. If the tack is not pointing down, click it to pin them. This way they will remain in place when you move your cursor away from the Toolbox.
4. The properties of the currently selected activity (or workflow if none is selected) are displayed in the Properties window, and the project files are displayed in the Solution Explorer. The Solution Explorer can be seen in the upper-right section and the Properties Window in the lower-right section of Figure 2.2.
5. Drag and drop a Code
activity onto the workflow.
6. Click the Code
activity and view its properties in the Property window. Click View, Properties Window, if it is not showing. The Name
, Description
, and Enabled
properties are common to all activities. Enabled
is particularly useful because it allows you to retain activities that do not execute on a workflow, which frequently comes in handy. It is equivalent to commenting out code. The ExecuteCode
property, on the other hand, is specific to the Code
activity. It points to a handler that executes when the Code
activity is executed. Figure 2.3 shows the Code
activity properties.
7. Double-click the Code
activity to create an event hander, and enter the code in the next code snippet:
Console.WriteLine("The time is {0}",
DateTime.Now.ToLongTimeString( ));
8. Open the workflow in design mode and drag and drop a Delay
activity below the Code
activity onto the workflow and set its TimeoutDuration
property to 00:00:10
.
9. Add another Code
activity below the Delay
activity, double-click it to get to its handler, and add the same code to its handler that you added to the preceding code activity’s handler.
Your workflow should now look like Figure 2.4. (If there are red exclamation marks, click them to see the errors, and then fix them.)
You have seen the two views of the workflow. The workflow designer is where you graphically create and view workflows. The code-beside is where you write code to support the activities on the workflow and add variables among other tasks. The workflow designer is analogous to the graphical view of a Windows Form, and the code-beside is analogous to the code-behind of a Windows Form.
Add steps to pause the host so that you can see the text printed to the console by the workflow:
1. Double-click Program.cs
in the Solutions Explorer and insert the lines of code shown in the next code snippet below the line that has waitHandle.WaitOne( )
on it so that the content written to the console will not disappear before you can see it:
// Pause the display
Console.WriteLine("Press enter to continue.");
Console.Read( );
Program.cs
is the console host. We just added a couple of lines to force the host to pause and allow us to see the text printed to the console when the workflow completes. We cover hosting in more detail in Hours 3 and 17. In this hour, we are relying on the default host outside of these minor changes and a couple of parameters we’ll add shortly.
Building and debugging a workflow solution is the same as any .NET solution with the one exception that you can insert breakpoints on workflow activities. When debugging, you can use the standard F5, F10, and F11 (start, step over, step into) keys. You can step from workflow activities into workflow code and back out to workflow activities. This is part of the developer-friendly design experience provided by WF.
You will run the workflow three times in this exercise. The first time you will run it with no debugging. The second time you will insert a breakpoint on the first Code
activity and step into the code. The third time you will set the breakpoint in the code.
Let’s go through the steps to build and run the workflow now:
1. Press F5 to build and run the solution (remember to wait 10 seconds for the Delay
activity to complete before the second line prints).
2. You should see the results shown in Figure 2.5.
3. Double-click Workflow1 in the Solution Explorer to open the workflow in design mode.
4. Right-click the first Code
activity and select Breakpoint, Insert Breakpoint from the drop-down menu.
5. Press F5 again and notice that the workflow pauses at the breakpoint (see Figure 2.6).
6. Press F11 to step in to the Code
activity’s handler code.
7. Notice that you are placed in the source code that you entered. You may step though it and the workflow activities using the standard F10/F11/F5 .NET debugging keys.
8. When you’re finished stepping through, select the first Code
activity and remove its breakpoint by right-clicking it and selecting Breakpoint, Delete Breakpoint.
9. Double-click the second Code
activity and set a standard .NET breakpoint on the first line of its handler’s source code by left-clicking on the margin or pressing F9.
10. Run the workflow with F5 again and notice that it stops at the breakpoint.
11. Step through the workflow as you want.
12. When you’re finished, remove the breakpoints you set on the second Code
activity and in the code-beside file.
In this section, we will add an IfElse
activity to the workflow. The IfElse
activity can be thought of as a switch
statement with a break inserted in each branch to ensure that it exits after the first true
result is returned. Ensuring the correct IfElseBranch
executes requires that we delve into rules.
1. Open workflow1
in design mode and drag and drop an IfElse
activity anywhere on the workflow.
2. Drop the first Code
activity on the workflow into the left branch of the IfElse
activity and the second Code
activity on the workflow into the right branch.
3. Delete the Delay
activity from the workflow.
Click the left branch of the IfElse
activity. It is named ifElseBranchActivity1. Each branch of an IfElse
activity contains an IfElseBranch
activity, which are themselves activities. The activities inserted in IfElse
activities are identical (with slight differences not now relevant) to Sequence
activities. Sequence
activities, like the sequential workflow you are now creating, act as containers for other activities. If you like, add a Sequence
activity to the workflow and add other activities to it. Now delete the Sequence
activity and other activities you added. The significance of the IfElse
being a container for IfElseBranch
activities that are, in turn, containers for other activities will become evident as we build workflows throughout this book.
Let’s go though the steps to create a Code Condition.
1. Click the first red exclamation mark in the IfElse
activity, then click Property ‘Condition’ Is Not Set. You will now be into the Condition property, ready to input a rule to determine whether this IfElseBranch
should execute.
2. In the Properties panel, click the drop-down in the Condition property and select Code Condition.
3. Click the + at the left of the Condition property, enter CodeBasedCondition
into the Condition property, and press Enter.
You are placed in the CodeBasedCondition handler.
4. Hard-code the Code Condition to return true
by entering the following in the handler. (This is how WF returns a Boolean in a condition, and it represents the beginning of many uses of eventargs in WF):
e.Result = true;
Complete the following steps to configure the Code
activities.
1. Switch back to the workflow designer by double-clicking Workflow1.cs
in the Solution Explorer.
2. Double-click the Code
activity in the left branch and insert the following code (the cast is to get the activity name):
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine("{0} executed in the left branch", ca.Name);
3. Now it is time to update the right branch of the IfElse
activity (switch back to the workflow designer again).
4. We will leave the condition blank because we want the right branch to act as an else and to always execute if the other branches (branch in this case) do not.
5. Double-click the Code
activity in the right branch and replace the current code with:
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine("{0} executed in the right-hand branch", ca.Name);
6. Your workflow should now look like Figure 2.7. See Listing 2.1 directly following for a sample of what your code-beside should look like.
LISTING 2.1 Enhanced Workflow Code Listing
namespace FirstWorkflowProject
{
public sealed partial class Workflow1: SequentialWorkflowActivity
{
public Workflow1( )
{
InitializeComponent( );
}
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine("{0} executed in the left branch"
, ca.Name);
}
private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine("{0} executed in the right branch"
, ca.Name);
}
private void CodeCondition(object sender, ConditionalEventArgs e)
{
e.Result = true;
}
}
}
7. Press F5 to run the workflow. The Code
activity in the left branch, that is hard-coded to true, should execute and produce the results shown in Figure 2.8:
Go ahead and play around with the Code Condition if you want. You might set the true
to false
in the condition handler to see if the right branch executes, for instance. This represents our first entry into a workflow that features controls flow logic.
One reason for using WF is to make programs self-evident. Our current implementation, unfortunately, leaves much room for concern in this quest. All we know is that there is a decision that leads the workflow to take different paths. Let’s label our activities to improve workflow comprehensibility. As with all naming schemes, many approaches exist that may, for example, prefix the descriptive names with the type of activity and so on. The purpose of this exercise is solely to show off transparency, not to define an enterprise-level naming convention.
In the next steps, you will change the labels on the workflow activities to improve transparency.
1. Select the IfElse
activity and change its name to CreditEvaluation
.
2. Select the left branch and change its name to CreditPassed
, and then change the right branch to CreditFailed
.
3. Rename the Code
activity in the left branch ApproveOrder
and the one in the right branch RejectOrder
.
4. Look at the workflow to see the improvement. It now serves as a functioning flowchart.
You can now look at the workflow (as shown in Figure 2.9) and see that the purpose of the IfElse
activity is to evaluate credit. You can also see which respective paths represent passing and failing credit. The process is now conveyed by looking at the workflow—as it would be if looking at a flowchart.
WF can receive a dictionary object as a parameter from the host when a workflow starts, and the host can access the workflow’s public properties when the workflow completes; it’s very reminiscent of standard method communication patterns. This is done by adding the dictionary object as an additional parameter to the CreateWorkflow
method. We are going to use this method of communication in this section. However, this method of communication is usually not the preferred way to conduct host-workflow communication. Workflows are frequently long-running and require mid-process communication to, for example, escalate an approval request if not received on time.
Passing parameters as a dictionary object may be appropriate for workflows that do not require mid-process communication (although persistence described in Hour 3, “Learning Basic Hosting,” may be a problem) and to augment other communication methods. Maybe setup data exists that must be sent to the workflow and it is most convenient to send it to the workflow at startup. Nothing precludes doing this while also using other methods for mid-process communication. Other methods of communication are covered throughout this book beginning in Hour 4, “Learning Host-Workflow Data Exchange.”
.NET 3.5-specific methods of communication that use Windows Communication Foundation are covered in Hour 19, “Learning WF-WCF Integration.”
In the steps that follow, we will now change our Code Condition to compare the value passed in from the host to a constant that will be set on the workflow. This way we can run the workflow once with an amount less than and once with an amount larger than the constant and let the Code Condition determine approval or rejection.
We need to modify the host where we will add a dictionary object and add it to the call to run the workflow instance. We need to modify the code-beside by adding a public property with the same name as the dictionary parameter to enable the exchange.
1. Open Program.cs
and add a parameter above the line that instantiates the workflowInstance
(starts with WorkflowInstance instance
) with the following code:
// Add the parameters via a dictionary object
Dictionary<string, object> parameters = new Dictionary<string,
object>( );
parameters.Add("Amount", 900);
2. Add the parameters to the call to the WorkflowInstance.CreateWorkflow
method by replacing the current line that instantiates the workflow instance with the following code:
WorkflowInstance instance = workflowRuntime.CreateWorkflow
(typeof(FirstWorkflowProject.Workflow1),parameters);
3. Open Workflow1
in code view and add a property named Amount
below the constructor to receive the information passed to the workflow as shown:
private int amount;
public int Amount
{
get { return amount; }
set { amount = value; }
}
4. Add a constant below the property you just added to compare against the incoming value and to determine approval status:
// The approval threshold amount.
const int maxAmount = 1000;
5. Replace the current content (e.Result = true;)
of the CodeBasedCondition
handler with the code shown so that it properly evaluates the amount received from the host to the constant value in the workflow:
if (Amount < maxAmount)
e.Result = true;
else
e.Result = false;
6. Open the workflow in design mode, double-click the Code
activity in the left branch, and replace the contents in its handler with the following code to reflect its approval:
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine("Approval: {0} executed in the left-hand branch",
ca.Name);
7. Open the workflow in design mode, double-click the Code
activity in the right branch, and replace the contents in its handler with the following code to reflect its rejection:
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine("Rejection: {0} executed in the right-hand branch",
ca.Name);
8. Press F5 to run the workflow.
The workflow should approve the request because the value of 900 passed in from the host is less than the 1000 constant specified in the workflow, as shown in Figure 2.10.
9. Change the Amount parameter in Program.cs
to 2000 and run the workflow again, which will result in rejection.
You will learn to retrieve information from the workflow when covering the WorkflowCompleted
event in Hour 3, “Learning Basic Hosting.”
So far you have created Code Conditions to govern workflow control flow. You can also use Declarative Rule Conditions to do the same. Declarative Rules Conditions, or Declarative Rules for short, are stored as XML in .rules
files. When creating Code Conditions, you write code inside of a handler. When creating Declarative Rules, you use the Rules Dialog editor (unless you write the XML yourself).
The fact that Declarative Rules are stored in XML is important because rules can be changed at runtime without requiring compilation, can be accessed by tools, and even stored in a database. See Hour 12, “Working with the WF RuleSet
,” for more details on rules.
Let’s perform the next steps to add a third branch to the IfElse
activity:
1. Right-click between the second IfElse
branch (Figure 2.11) and the right border of the IfElse
activity and select Add Branch from the drop-down.
2. Drag (move) the Code
activity from the middle IfElse
branch to the newly added third branch.
3. Rename the second branch ApprovalRequired
and the third branch CreditFailed
. The workflow should now appear like Figure 2.12:
4. Drag and drop a (new) Code
activity and insert it in the second branch.
5. Double-click the new Code
activity and add the following snippet to its handler:
// Case the sender object to a codeactivity
CodeActivity ca = sender as CodeActivity;
// Print the code activity name
Console.WriteLine
("Additional approval required: {0} executed in the middle branch"
, ca.Name);
Let’s go though the next steps to create a Declarative Rule Condition.
1. Click the red exclamation mark, and then click Property ‘Condition’ Is Not Set. You will now be in the Condition
property, ready to input a rule to determine whether this IfElseBranch
should execute.
2. Click the drop-down in the Condition
property and select Declarative Rule Condition.
3. Click the +
at the left of the Condition property, enter DeclarativeRuleCondition
in the ConditionName
property, and press Enter.
4. Click the ellipses button in the ConditionName
property and click the Edit button.
5. Enter this.Amount < 2000
into the Rule Condition Editor.
6. You should have the following dialog with the expression you entered in it (see Figure 2.13):
7. Click the OK button twice to save your Declarative Rule and exit both dialogs.
8. Change the Amount in the Dictionary Object in Program.cs
to 1200
and run the workflow.
9. You should now see that additional approval is required because the amount is more than 1,000 and less than 2,000, as shown in Figure 2.14.
10. Double-click the .rules
file in the Solution Explorer below workflow1.cs
. (Expand workflow1.cs
, if necessary.)
11. The Declarative Rule you entered is shown in Figure 2.15. It is based on a combination of the CodeDom (.NET code serialization technology) and XML, so it is very verbose. However, you do not need to look at this file very often. It is meant for tools to execute and analyze.
The next logical step is to add the logic to require approval when the middle branch (approval required) is executed. This, however, requires in-flight workflow access. You will see examples of how to accomplish this when you work with more advanced host-workflow data exchange techniques, which you will do beginning with Hour 5, “Creating an Escalation Workflow.”
We used the default Workflow1.cs
created by the sequential workflow project template. This generates what is known as a code-only workflow, which means that the controls added to the workflow are contained in a partial class with a designer.cs
extension. These controls are loaded in the .cs
portion of the class by a call to InitializeComponent
in the constructor. This is exactly how a Windows Form is structured. In the next steps, you will walk through the project structure for a project that contains one code-only workflow.
1. Right-click Workflow1.cs
in the Solution Explorer and choose View Code, which contains the code-beside logic. It is a partial class that augments the workflow and contains the code written in this lab.
2. Double-click Workflow1.designer.cs
in the Solution Explorer to open it and click the + next to the Designer Generated Code region. Workflow1.designer.cs
is also a partial class (the other half of the Workflow1
class) that contains the activities added to the workflow. This file is the programmatic representation of the graphical display contained in the workflow designer.
3. For instance, Listing 2.2 contains the code in Workflow1.designer.cs
that adds a Code
activity to the workflow:
LISTING 2.2 Add a Code
Activity in Code
private void InitializeComponent( )
{
// other code
this.codeActivity2 = new System.Workflow.Activities.CodeActivity( );
this.codeActivity2.Name = "codeActivity2";
this.codeActivity2.ExecuteCode +=
new System.EventHandler(this.codeActivity2_ExecuteCode);
// it is then added to the IfElse activity that is
// added to the workflow
// remmaining code
}
4. Program.cs
represents the host in this example. In most cases the host will be another application because a console application isn’t generally a useful place to have long running workflows.
5. As you’ve already seen, a .rules
file is created when declarative rules are used, which is completely independent of the type of workflow.
If you prefer you can create the workflow via code. Whether created in code or graphically, the code and designer should remain synchronized, although this is not always the case. Therefore, be prepared to lose the ability to view your workflow if you create it programatically.
The default option is to create a code-only workflow. In this section you learn to add a XAML + code workflow. This will store the workflow activities in XAML, and the code-beside remains in code. The advantage to this route is that the workflows themselves are more accessible by tools. However, there are no real compilation advantages to this option versus its code-only compatriot; both must be compiled.
The next steps walk you through creating a XAML + Code workflow.
1. Right-click FirstWorkflowProject in the Solution Explorer and choose Add, New Item.
2. Select Workflow in the left pane and select the Sequential Workflow (with code separation) item template.
3. Enter Workflow2XOMLandCode.xoml
into the Name dialog box and click the Add button.
4. You should now have an empty workflow designer form.
5. Drag and drop a Code
activity, Delay
activity, and another Code
activity onto the workflow, in that order.
6. Double-click the first Code
activity to open its handler and enter the following:
Console.WriteLine("In the first code activity.");
7. Open Workflow2XOMLandCode in design mode. Then double-click the second Code
activity to open its handler and enter the following (be careful to go back to the workflow designer for the new workflow):
Console.WriteLine("In the second code activity.");
8. Open Workflow2XOMLandCode in design mode. Change the TimeoutDuration on the Delay activity to 00:00:10
seconds.
Let’s take a look at the XAML workflow in the following steps.
1. Save the project by selecting File, Save All.
2. Open Workflow2XOMLandCode.xoml
in the XML editor by right-clicking it, selecting Open With, XML Editor, and pressing OK. (Click Yes to dialogs that warn that files are open and request that you save, if you did not click Save, All in the previous step.)
3. The workflow is now expressed in XAML as shown:
<SequentialWorkflowActivity
x:Class="FirstWorkflowProject.Workflow2XOMLandCode"
x:Name="Workflow2XOMLandCode"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<CodeActivity x:Name="codeActivity1"
ExecuteCode="codeActivity1_ExecuteCode" />
<DelayActivity TimeoutDuration="00:00:10" x:Name="delayActivity1" />
<CodeActivity x:Name="codeActivity2"
ExecuteCode="codeActivity2_ExecuteCode" />
</SequentialWorkflowActivity>
The file Workflow2XOMLandCode.xoml
would be named Workflow2XOMLandCode.designer.cs
if this was a code-only workflow. The workflow model is now represented in this XAML file rather than in the constructor of a .designer.cs
file. The x:Class="FirstWorklfowProject.Workflow2XOMLandCode"
points to the code-beside class that supporrs the workflow expressed in XAML.
As explained in Hour 1, “Understanding Windows Workflow Foundation,” the contents of .xoml
files are standard XAML; .xoml
is used so that browsers will not attempt to render it.
XAML + code workflows are compiled as if they were code-only workflows. Therefore, the syntax to load and execute them is identical to that of a code-only workflow. The only change in this section is that you will point the host to Workflow2XOMLandCode
instead of Workflow1
in the next steps.
1. Change the host program to point to the new workflow by replacing the current line that instantiates the workflow instance (the one that starts with WorkflowInstance instance =
) with the code shown next:
WorkflowInstance instance =
workflowRuntime.CreateWorkflow
(typeof(FirstWorkflowProject. Workflow2XOMLandCode));
2. Run the workflow and you will see the results shown in Figure 2.17. It runs as if it was created entirely in code. There is no difference from an execution standpoint.
We will create a XAML-only version of our workflow in this task. Unlike its predecessors, limitations exist to XAML-only workflows. They do not support code very well. Therefore, they do not support Code
activities because they do not have a code-beside file where code can be stored.
If XAML-only workflows are limited, why use them? They can run without compilation. This enables all sorts of scenarios ranging from business analyst-friendly workflow designers to retrieving workflows from a database. The SharePoint Designer featured in SharePoint workflow exemplifies a business analyst-friendly designer that allows workflows to be created and run without compilation.
There are two ways to work around the fact that XAML workflows do not allow code. One is to create custom activities (described in Hours 20 to 24) that contain the custom code in ready-to-use activities. This is one of WF’s major features. The other is to embed the code directly in the XAML, which is not a great option because it requires compilation.
Creating XAML-only workflows does require a few additional steps.
In the next steps, you will now create a new workflow using the same code separation template. You will then manually modify it to be a XAML-only workflow. The main change you will make is to remove the pointer the code-beside class used in XAML plus code workflows. This class is neither needed nor allowed in XAML-only workflows. You will also configure the XAML file to not be compiled and to be copied to the bindebug directory.
1. Right-click FirstWorkflowProject
in the Solution Explorer and choose Add, New Item.
2. Select Workflow in the left pane and select the Sequential Workflow (with code separation) item template.
3. Enter Workflow2XOMLOnly.xoml
into the Name dialog and click the Add button.
You should now have an empty workflow designer form.
4. Add a Delay
activity to the workflow.
5. Save the project by selecting File, Save All.
6. Open Workflow2XOMLOnly.xoml
in the XML editor by right-clicking it, selecting Open With, XML Editor, and clicking OK. (Click Yes to dialogs that warn that files are open and request that you save, if you did not Save, All in the last step.)
7. Remove the line that points to the code-beside class x:Class="FirstWorkflowProject
. Workflow2XOMLOnly
and save the project again.
8. Select Workflow2XOMLOnly.xoml
in Solution Explorer and change its Copy to Output
property to Copy If Newer and its Build Action
property to None.
9. Build the project. Make sure it builds successfully and verify that the Workflow2XOMLOnly.xoml
file was copied to the C:SamsWf24hrsHoursHour02ASpinAroundWFFirstWorkflowProjectFirstWorkflowProjectinDebug
directory.
You will now load the XAML workflow as an XML document in the next steps. WF will load and execute the activities on the workflow without a separate compilation step. The workflow is currently started by passing a .NET type to the WorkflowRuntime.CreateWorkflow
method. You will create a text reader that contains the XOML workflow information and then pass it to the CreateWorkflow
method.
1. Open Program.cs
and replace the line of code that starts with WorkflowInstance instance = WorkflowRuntime.CreateWorkflow
with the following two lines of code to create the XML text reader and pass it to the CreateWorkflow
method:
XmlTextReader xmltr = new XmlTextReader(@
"C:SamsWf24hrsHoursHour02ASpinAroundWFFirstWorkflowProjectFirstWorkflo
wProjectinDebugWorkflow2XOMLOnly.xoml");
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(xmltr);
2. Add the following using
directive below the other using statement at the top of the file:
using System.Xml;
3. Run the workflow. The only results you will see are the host requesting that you press any key after the delay.
This example is obviously contrived. The XAML-only workflow option is useful only in conjunction with custom activities of which there must be enough to create a workflow without code. For example, if there were Customer
, Credit
, and other activities, it would be possible to create a credit process workflow with the combination of BAL and these custom activities that did not require code. In this case, XAML-only workflows are attractive. As mentioned already, the SharePoint Designer uses XAML-only workflows to allow knowledge workers to create workflows without compilation, and they can create reasonably functional workflows that contain multiple levels of escalation and dynamic task assignment, among other features.
XAML-only workflows cannot receive parameters via a Dictionary Object and cannot have constructors. There are other items you should know if you’re working with moderate-to-complex XAML workflows. These topics are not covered in this book. I recommend looking at this blog entry if you want to learn more about XAML-only workflows: http://blogs.msdn.com/endpoint/archive/2008/07/06/download-posted-wf-xaml-workshop.aspx.
Going forward, it is likely there will be better all-around XAML support in WF because its ability to execute without compilation and the ability for tools to access it are key to WF’s vision.
This hour featured a walk through a wide range of basic WF functionality. It covered everything from project structure, to rules, to XAML-only workflows. It built on the conceptual walkthrough and installation provided in Hour 1, “Understanding Windows Workflow Foundation.” You need to learn a little more about hosting, which you will do in Hour 3, “Learning Basic Hosting.” After that, you are ready to build on what you learned here and create workflows that manage long-running state, approval scenarios, and escalation.
18.117.142.169