EventHandlingScope
and Strongly Typed ActivitiesWhat You’ll Learn in This Hour:
Basic usage of an EventHandlingScope
activity
Using the EventHandlingScope
and Replicator
activity in conjunction
Creation of the engine of a highly functional and dynamic approval-centric workflow
Using the wca.exe
utility to create strongly typed activities
Modeling a workflow using strongly typed activities
The EventHandlingScope
activity is a multifaceted activity that supports a default path while listening to events at the same time. The default path is supported by a Sequence
activity that runs activities through in normal sequential progression. While the sequential path is processing, the EventDrivenActivity
’s event handler’s portion listens for and acts on events.
The capability to conduct a flow while listening to events is useful in at least a couple of scenarios. The first is to support events that may occur throughout the workflow’s life cycle while it is processing, such as canceling the workflow, adding an approver, and changing approvers. The second is to allow the workflow to process events for a specific period of time—for example, if allowing orders to be shipped by FedEx, UPS, and another carrier during a one-hour time period.
Hour 5, “Creating an Escalation Workflow,” introduced the Listen
activity that permits two or more branches to be equipped with blocking activities (for example, HandleExternalEvent
or Delay
) as their first activities. The EventHandlingScope
activity also permits multiple branches to be equipped with blocking activities as their first child. The difference is that the EventHandlingScope
activity permits the events to reoccur, whereas the Listen
activity processes one event on one branch based on the first event or expired timer it receives.
Finally, after manually binding HandleExternalEvent
and CallExternalMethod
activities to local service interfaces throughout this book, you will learn to create strongly typed activities already bound to interfaces, which simplifies adding them to workflows.
See previous hours if you need help creating projects or solutions.
Follow the next steps to set up the solution.
1. Open the solution named EventHandlingScopeWorkflow
in the C:SamsWf24hrsHoursHour10EventHandlingScopeLab1EventHandlingScopeWorkflow
directory with a project named LocalServices
and another named EventHandlingScopeHostForm
.
2. Add a Sequential Workflow Library
project to the solution and name it EventHandlingScopeWorkflows
.
3. Add a reference to the LocalServices
project and to System.Windows.Forms
.
4. Set a reference from the EventHandlingScopeHostForm
to both the LocalServices
and EventHandlingScopeWorkflows
projects.
In this section, you configure the EventHandlingScope
activity across its different elements.
First is a brief prelude to XAML workflows because you will create them in this hour and they are one of the major pieces of the WF puzzle. Workflows can be laid out in XAML as discussed in Hour 2, “A Spin Around Windows Workflow Foundation.” So far (with the exception in Hour 2), the default workflow format has been used, which lays out the workflow via code in the constructor, in a manner much like a Windows Form. In XAML workflows, the layout resides in a .XOML
file (that again contains standard XAML but the extension prohibits browsers from attempting to render it). You are not specifying a XAML-only file, and so there will still be a code-beside file. The change will be limited to where the layout is specified. The reason for choosing XAML over code is that tools can operate against it much more effectively. XAML can also make looking at the logic easier and it is helpful to look at the EventHandlingScope
activity in XAML to understand what it does.
In the next steps, you add an EventHandlingScope
activity and add activities to its mainline element—the one that processes sequentially until completed.
1. Delete Workflows1.cs
from the EventHandlingScopeWorkflows
project.
2. Right-click the EventHandlingScopeWorkflows
project, choose Add, New Item, choose the Sequential Workflow (with code separation) project template, and name it EventHandlingScopeWorkflow
.
3. Add the following using
directive to the workflow code-beside file:
using System.Windows.Forms;
4. Add an EventHandlingScope
activity.
5. Add a Sequence
activity to the EventHandlingScope
activity.
6. Add a Code
activity to the Sequence
activity.
7. Add a Delay
activity below the Code
activity.
8. Add another Code
activity below the Delay
activity.
You have completed the mainline processing element of the EventHandlingScope
activity. In the next steps, you will configure its listeners that will be called on zero or more times during mainline workflow execution. This is useful because in many approval workflows it is necessary to be able to change approver midflight, and it may always be handy to cancel the workflow. Therefore, these two events are trapped in the EventHandlingScope
event handling section, where they can be trapped throughout the EventHandlingScope
activity’s sequential execution.
1. Right-click the EventHandlingScope
activity and notice the View Event Handlers option below the standard views, which is available for most control flow activities.
2. Right-click the EventHandlingScope
activity again and select View Event Handlers. The EventHandlingScope
activity should now look like Figure 10.2.
3. Place an EventDriven
activity in the little rectangle (the film strip) that goes across the upper half of the EventHandlingScope
activity and name it CancelWorkflow
.
4. Place another EventDriven
activity next to the first EventDriven
in the film strip and name it AddApprover
.
5. Click the CancelWorkflow EventDriven
activity and drag and drop a HandleExternalEvent
activity into the middle of the EventHandlingScope
activity where it says Drop Activities Here
.
6. Place a Code
activity below the HandleExternalEvent
activity.
7. Click on the AddApprover EventDriven
activity and add a HandleExternalEvent
activity to it.
8. Place a Code
activity below this HandleExternalEvent
activity as well.
9. Click either activity in the CancelWorkflow EventDriven
activity, and your EventHandlingScope
activity should now look like Figure 10.3.
In the next steps, you configure the child activities in the EventHandlingScope
activity’s sequential section.
1. Right-click the EventHandlingScope
activity and choose view EventHandlingScope. You should now see your two Code
activities and one Delay
activity that make up the standard processing (as seen in Figure 10.1).
2. Double-click the first Code
activity and add the following code to its handler:
MessageBox.Show("The EventHandlingScope activity has started at "
+ System.DateTime.Now.ToLongTimeString());
3. Set the Delay
activity’s TimeoutDuration
property to 00:00:30
.
4. Double-click the second Code
activity and add the following code to its handler:
In this section, you configure the child activities in the EventHandlingScope
activity’s Event Handlers
section.
In the next steps, you configure the CancelWorkflow EventDriven
activity.
1. Right-click the EventHandlingScope
activity and select View Event Handlers.
2. Click the CancelWorkflow EventDriven
activity.
3. Click the HandleExternalEvent
activity and set its InterfaceType
property to IEventHandlingScopeBasicLocalService
and its EventName
property to OrderWorkflowCancel
. (See Hour 4, “Learning Host-Workflow Data Exchange,” if you need help binding activities to local services.)
4. Double-click the Code
activity below the HandleExternalEvent
activity and add the following code to its handler:
MessageBox.Show("Workflow canceled at "
+ System.DateTime.Now.ToLongTimeString());
In the next steps, you configure the AddApprover EventDriven
activity.
1. Click the AddApprover EventDriven
activity.
2. Click the HandleExternalEvent
activity and set its InterfaceType
property to IEventHandlingScopeBasicLocalService
and its EventName
property to OrderWorkflowAddApprover
.
3. Click the Code
activity below the HandleExternalEvent
activity and add the following code to its handler:
MessageBox.Show("Approver added at"
+ System.DateTime.Now.ToLongTimeString());
You will now test the EventHandlingScope
activity in the next steps by running a form with three buttons. The first allows you to start the workflow. The second allows you to continue to raise the cancel workflow event while the workflow is still running. The third allows you to continue to add an approver to the workflow. The workflow will run for 30 seconds after it is started, based on the Delay
activity configuration.
In the next steps you view the EventHandlingScope
activity’s XAML representation.
1. Right-click the EventHandlingScopeWorkflow.xoml
file in the Solution Explorer, select Open With, select XML editor, and click OK.
2. Listing 10.1 contains the logic for the EventHandlingScope
activity. I stripped much of the details including references to the interface for brevity. As you can see, there are two main elements of the EventHandlingScope
activity—one for the sequential portion and the other for the event handler’s portion. Looking at workflows and activities in XAML can be a productive way to get a picture of the activity or workflow.
LISTING 10.1 EventHandlingScopeWorkflow
XAML View
<EventHandlingScopeActivity x:Name="eventHandlingScopeActivity1">
<SequenceActivity x:Name="sequenceActivity1">
<CodeActivity x:Name="codeActivity1"/>
<DelayActivityx:Name="delayActivity1" />
<CodeActivity x:Name="codeActivity2"/>
</SequenceActivity>
<EventHandlersActivity x:Name="eventHandlersActivity1">
<EventDrivenActivity x:Name="CancelWorkflow">
<HandleExternalEventActivity
x:Name="handleExternalEventActivity1"
EventName="OrderWorkflowCancel"/>
<CodeActivity x:Name="codeActivity3"/>
</EventDrivenActivity>
<EventDrivenActivity x:Name="AddApprover">
<HandleExternalEventActivity
x:Name="handleExternalEventActivity2"
EventName="OrderWorkflowAddAppprover"/>
<CodeActivity x:Name="codeActivity4"/>
</EventDrivenActivity>
</EventHandlersActivity>
</EventHandlingScopeActivity>
By now you have much of the gist of the EventHandlingScope
activity. This section combines the EventHandlingScope
activity with the Replicator
. The Replicator
provides the capability to provision n number of users when the workflow begins processing and the EventHandlingScope
has the ability to alter the approvers during the workflow’s life cycle. This combination supplies a solid platform for many approval scenarios where flexibility is necessary throughout the process—for example, as approvers go on vacation or new approvers are required. In fact, if you look at the source code provided with the SharePoint SDK, most of the workflows are highly dependent on these two activities to allow for flexible levels of approval, flexible number and style of approval, and changes throughout their life cycle.
Follow the next steps to open and configure the WorkflowEventHandlingScopeReplicator
solution.
1. Open the solution named WorkflowEventHandlingScopeReplicator
in the C:SamsWf24hrsHoursHour10EventHandlingScopeLab2WorkflowEventHandlingScopeReplicator
directory with a project named LocalServices
and another named EventHandlingScopeReplicatorForm
.
2. Add a Sequential Workflow Library
project to the solution and name it EventHandlingScopeWorkflows
.
3. Add a reference to the LocalServices
project and to System.Windows.Forms
.
4. Delete Workflow1.cs
and add a new workflow named EventHandlingScopeReplicatorWorkflow
; specify that it uses code separation.
5. Add a reference from the EventHandlingScopeReplicatorForm
project to the EventHandlingScopeWorkflows
project.
In the subsections of this section, you will configure the various EventHandlingScope
activity views.
In the next steps, you add activities to the EventHandlingScope
activity’s sequential view.
1. Add an EventHandlingScope
activity to the workflow.
2. Add a Replicator
activity to the EventHandlingScope
activity.
3. Add a Sequence
activity to the Replicator
activity.
4. Add a CallExternalMethod
activity and a HandleExternalEvent
activity to the Sequence
activity.
5. The overall layout of your workflow should look like Figure 10.5, although it will still have exclamation marks because it is not yet figured.
In the next steps, you add activities to the EventHandlingScope
activity’s Event Handlers view.
1. Right-click the EventHandlingScope
activity and choose its Event Handlers view.
2. Drop an EventDriven
activity into its film strip and add a HandleExternalEvent
activity to it.
3. Drop another EventDriven
activity into its film strip and add a HandleExternalEvent
activity to it.
4. Drop a third EventDriven
activity into its film strip and add a HandleExternalEvent
activity to it.
5. Click the first EventDriven
activity, and your EventHandlingScope
activity should look like Figure 10.6.
In the next steps, you configure the activities in the sequential view.
1. Right-click the EventHandlingScope
activity and set its view to the EventHandlingScope view.
2. Click the CallExternalMethod
activity; then set its InterfaceType
property to the IOrderCorrelationLocalService
and its MethodName
property to GetResponse
. (Be careful to choose the correct interface because there are two.)
3. Set its CorrelationToken
property to TheToken
and its OwnerActivityName
property to sequenceActivity1
.
4. Click the HandleExternalEvent
activity, set its InterfaceType
property to the IOrderCorrelationLocalService
, and set its EventName
property to OrderWorkflowApprove
.
5. Set its CorrelationToken
property to TheToken
.
In the next steps, you configure the activities in the Event Handlers view.
1. Set the EventHandlingScope
activity to its Event Handlers view.
2. Click the left-hand EventDriven
activity and name it CancelWorkflow
.
3. Click the HandleExternalEvent
activity in the CancelWorkflow EventDriven
activity, set its InterfaceType
property to IEventHandlingScopeBasicLocalService
, and set its EventName
property to OrderWorkflowCancel
.
4. Click the middle EventDriven
activity and name it AddApprover
.
5. Click the HandleExternalEvent
activity in the AddApprover EventDriven
activity, set its InterfaceType
property to IEventHandlingScopeBasicLocalService
, and set its EventName
property to OrderWorkflowAddApprover
.
6. Click the right EventDriven
activity and name it DeleteApprover
.
7. Click the HandleExternalEvent
activity in the DeleteApprover EventDriven
activity, set its InterfaceType
property to IEventHandlingScopeBasicLocalService
, and set its EventName
property to OrderWorkflowDeleteApprover
.
The Approvers
property you create will be an array list because this time the workflow will accept a list of approvers from the host form rather than manufacturing approvers based on a total number.
1. Add the following using
directive to the workflow code-beside file:
using System.Windows.Forms;
2. Add the following variable to the top of the code-beside file class. (No constructor exists, because the workflow is expressed in XAML.)
int counter = 0;
3. Create a new DependencyProperty
named OrderAmount
by right-clicking in the code-beside file below the variable you just added. Select Insert Snippet, double-click Other, Workflow, select the Dependency Property, Property choice, and name it Approvers
(leave the Property suffix). Press Tab, set its type to ArrayList, and press Enter to leave the remaining defaults.
4. Add another dependency property, name it ApprovalStyle
, and accept all remaining defaults.
In the next steps, you add the code to execute when the Replicator
and its children are initialized. This is nearly identical to the code used the previous hour. The major difference is that it accepts Approvers from the form, thereby eliminating the need to combine Approver + counter to manufacture approvers.
1. Click the Replicator
activity (remember to switch to the EventHandlingScope
activity view if it is not shown), enter RepInitialized
in its Initialized
property, and enter the following code in its handler:
replicatorActivity1.InitialChildData = Approvers;
// Specify whether child instances should execute in serial or
parallel
if (ApprovalStyle == "Parallel")
replicatorActivity1.ExecutionType = ExecutionType.Parallel;
else
replicatorActivity1.ExecutionType = ExecutionType.Sequence;
2. Enter RepChildInit
in its ChildInitialized
property, and enter the following code in its handler:
// Extract the "correct" CallExtnernalMethodActivity
CallExternalMethodActivity act =
e.Activity.GetActivityByName("callExternalMethodActivity1",
true)
as CallExternalMethodActivity;
act.ParameterBindings["approver"].Value =
Approvers[counter].ToString();
counter = counter + 1;
This is where the majority of the new code resides. You will trap the Invoked
methods of each of the HandleExternalMethod
activities to cancel the workflow, add an approver, or delete an approver. Approvers are added and removed from the Replicator.CurrentChildData
property, which carries the replicator child data as the Replicator
activity executes.
You will display a message when the workflow is canceled (cancellation is covered in Hour 16, “Working with Exceptions, Compensation, and Transactions,” but you will enter code to carry out the other two choices now.
In the next steps you update the Invoked
handlers of the HandleExternalEvent
activities.
1. Click the HandleExternalEvent
activity in the CancelWorkflow EventDriven
activity (remember to switch the activity view if necessary), enter CancelWorkflowInvoke
in its Invoked
property, and enter the following code in its handler:
SamsWFBook.OrderCancelEventArgs ea = e as
SamsWFBook.OrderCancelEventArgs;
MessageBox.Show(ea.Reason.ToString());
2. Click the HandleExternalEvent
activity in the AddApprovers EventDriven
activity, enter AddApproverInvoked
in its Invoked
property, and enter the following code in its handler:
this.replicatorActivity1.CurrentChildData.Add
((e as SamsWFBook.OrderApproverEventArgs).Approver);
Approvers.Add((e as SamsWFBook.OrderApproverEventArgs).Approver);
3. Click the HandleExternalEvent
activity in the DeleteApprovers EventDriven
activity, enter DeleteApproverInvoked
in its Invoked
property, and enter the following code in its handler:
this.replicatorActivity1.CurrentChildData.Remove
((e as SamsWFBook.OrderApproverEventArgs).Approver);
Approvers.Remove((e as
SamsWFBook.OrderApproverEventArgs).Approver);
The form has been changed. It allows you to enter the name of up to three approvers and to cancel the workflow, add approvers, and to delete approvers midflight. The workflow queues are updated each time you add or remove an approver. The new form is shown in Figure 10.7.
Follow the next steps to load the form, enter the values, and run the workflow.
1. Run the project and enter Robert
in Approver 1, Patricia
in Approver 2, and Matthew
in Approver 3.
2. Set the form to process in parallel and click the Create Order button.
3. The Queues text box should show entries for Robert
, Patricia
, and Matthew
.
4. Enter New Approver
in the text box alongside the Add Approver button, and then click the Add Approver button.
5. The Queues text box should now contain a fourth entry for the new approver. You have just updated a workflow midflight, as shown in Figure 10.8.
6. Enter Robert
in the text box alongside the Delete Approver button and then click the Delete Approver button.
7. The Queues text box should now contain only three approvers.
8. Click the Cancel Workflow button and you will be presented with a dialog box.
9. Now select the other approvers by entering a name in the Queues
text box and clicking Submit. Do so for all remaining approvers in any order and then the EventHandlingScope
activity and in turn the workflow will complete.
The WCA.exe
utility enables the creation of strongly typed communication activities (CallExternalMethod
and HandleExternalEvent
) that can be placed on the workflow where their properties can be set. The general advantages are that there is no need to point them to an interface and select the correct method or event. It is also more performant because the strong typing eliminates the need to use reflection to gather the type information at runtime. They can also be used to store additional information when integrating with other systems, as will be explained shortly. For communication activities that will be used frequently, strong typing is useful.
1. Shell out to a command prompt and enter the following to go to the bin directory: C:SamsWf24hrsHoursHour10EventHandlingScopeLab2WorkflowEventHandlingScopeReplicatorEventHandlingScopeWorkflowsinDebug
.
2. Enter "C:Program FilesMicrosoft SDKsWindowsv6.0Bin"wca.exe
to see all options available. (On Windows Server 2003 I had to include the quotes around the path and place wca.exe
outside the quotes as shown. Your path might vary for WCA.exe
. If so, search for it.)
3. Enter "C:Program FilesMicrosoft SDKsWindowsv6.0Bin"wca.exe localservices.dll
to run the WCA utility on the local service for this project.
4. IOrderCorrelationLocalService.Invoke.cs
and IOrderCorrelationLocalService.Sink.cs
will be generated. The first contains the CallExternalMethod
activities and the latter contains the HandleExternalMethod
activities. (There is also an equivalent duo created for the IEventHandlingScopeBasicLocalService
local service, which we will not use.)
5. Add a new Class Library
project named StronglyTypedActivities
to the solution and add the IOrderCorrelationLocalService
files created above using the Project, Add Existing Item option.
6. Delete Class1.cs
.
7. Add references to System.Workflow.Activities
, System.Workflow.ComponentModel
, and System.Drawing
. Also reference the LocalServices
project.
8. Build the project.
9. Open the EventHandlingScopeReplicatorWorkflow
in design model and you will see that the GetResponse
and OrderWorkflowApprove
activities have been added under the new StronglyTypedActivities section (as shown in Figure 10.9). They are available to all projects in the current solution. In Hour 20, “Creating Basic Custom Activities,” you will learn to make them available to all projects, including those outside of this solution.
Because you will now add the same communication activities to multiple branches, reducing the configuration will streamline the process.
Follow the next steps to add strongly typed communication activities to the workflow.
1. Disable the EventHandlingScope
activity.
2. Add a Parallel
activity at the end of the workflow and change its name to ParallelWithStronglyTypedActivities
.
3. Add a GetResponse
and an OnWorkOrderApprove
activity, in that order, to both branches of the Parallel
activity. The Parallel
activity should now look like Figure 10.10.
4. Click the GetResponse
activity in the left branch and notice that its properties are different from those of a standard CallExternalMethod
activity (as shown in Figure 10.11). It contains no InterfaceType
or MethodName
properties; they are unnecessary because these are part of the activity, which makes the activity strongly typed.
5. Enter Branch1Token
in the GetResponse
activity CorrelationToken
property and then select the enclosing Sequence
activity as the owner (in my case it is sequenceActivity2).
6. Enter branch1
in the approver property.
7. Click the OrderWorkflowApprove
activity in the left branch and notice its new properties (as shown in Figure 10.12).
8. Enter branch1
in its approver property and select Branch1Token in its CorrelationToken
property.
9. Configure the right branch strongly typed GetResponse
activity using Branch2Token
as the CorrelationToken
, its enclosing Sequence
activity as its OwnerActivityName
, and branch2
as its approver property.
10. Configure the right branch strongly typed OrderWorkflowApprove
activity using Branch2Token
as the CorrelationToken
property and branch2
as its approver property.
11. Run the workflow, do not enter any data on the form, and click Create Order.
You should see the results shown in Figure 10.13, which represent the two queues created by the HandleExternalEvent
activities awaiting a response.
12. Enter the approvers (branch1, then branch2) one at a time in the Approver Name
text box and click Submit after each to respond to the events and complete the workflow. (This is a Parallel
activity and not a Listen
, so both events will be raised concurrently.)
If you like, open IOrderCorrelationLocalService.Invokes.cs
and IOrderCorrelationLocalService.Sinks.cs
to see the source code behind these strongly typed activities. Although used here for convenience, the extra attributes can also be used to communicate with external systems. For example, SharePoint’s WF implementation features numerous task-centric activities that are strongly typed activities with attributes, such as task name, due date, and so on, that are used to interact with SharePoint tasks.
A very powerful activity was introduced in this hour: the EventHandlingScope
. Its general usage was explored in the first section. The second section walked though how to use this activity in conjunction with the Replicator
to create highly flexible workflows. These workflows benefit from the Replicator
’s known abilities to configure a number of approvers when the workflow starts and to process in parallel or sequence while allowing for workflow-wide event handlers to trap and process events, such as to add an approver or cancel a workflow. A new capability of the Replicator
to update its Replicator.CurrentChildData
property was also used, which is changed when an event to add or delete approvers is trapped during workflow execution. Although you still have to create the distribution vehicle to reach the users—email, InfoPath forms, SharePoint tasks, or other—this workflow provides the underpinnings for many powerful approval-centric workflows. One feature you may want to add is another Replicator
so that the number of approval levels can be specified per workflow as well. So far, all our samples process one level of approvals across all approvers. Finally, strongly typed activities were created and modeled on a workflow.
18.117.91.187