Out-of-the-Box Activities


The following sections cover the out-of-the-box activities included in the Windows Workflow Foundation API. Each section begins by showing the class definition for an activity and then provides useful information, including whether you can inherit from the activity, which class the activity inherits from, and any interfaces the activity implements. There are different base classes an activity can inherit from and other miscellaneous interfaces that add functionality to an activity.

In addition, a few activities are specific to certain types of workflows. More specifically, activities such as State and SetState can be used only in state-machine workflows. Whenever an activity has a requirement such as this, it is pointed out in the text.

The CallExternalMethod Activity

The syntax of the CallExternalMethod activity is as follows:

  public class CallExternalMethodActivity : Activity, IDynamicPropertyTypeProvider 

This activity is a vital component of the local communication services (covered in Chapter 5). To use this activity, you must set the InterfaceType and MethodName properties so that the workflow knows which external method to call. You set these properties from the properties window in Visual Studio, as described in Chapter 5. The InterfaceType property uses the .NET type browser to display and select the appropriate communication interface.

If you have not already done so, first you need to add the ExternalDataExchangeService to the workflow runtime’s services collection. You can then implement the interface set to the InterfaceType property on the ExternalDataExchangeService communication service class.

You use the CallExternalMethod activity’s ParameterBindings property to map parameters defined by the method referenced in the MethodName property. This property is of type WorkflowParameter BindingCollection and maps parameter names to fields in the workflow code. WorkflowParameter BindingCollection inherits from KeyedCollection<string, WorkflowParameterBinding>, which in turn maps a string to a parameter binding class. Return values work the same way.

The Code Activity

The syntax of the Code activity is as follows:

  public sealed class CodeActivity : Activity 

This activity is the utility player of the workflow activities. It is extremely useful for one-off scenarios that can be accomplished with a couple of lines of code. The Code activity works by exposing a single event called ExecuteCode, which fires when the activity is ready to execute.

In the corresponding code file, you need to include an event handler for the ExecuteCode event as well as your implementation of the desired functionality for the activity. You can use a variety of code types for this activity, from modifying workflow variables to performing calculations.

The ExecuteCode event handler executes on the same thread as the workflow and in a synchronous manner, meaning that the workflow does not proceed until the handler code has completed. Because of this, you should use the Code activity for relativity simple and short-running pieces of code (similar to code that runs on the UI thread of a Windows Forms application).

You may open up a workflow and see a load of Code activities strewn about. This is the antithesis of the workflow development paradigm. Not that using the Code activity is a bad thing in the right situation, but if you find yourself continually writing code behind the workflow, developing a new activity might be a better solution. As in object-oriented development, this enables you to reuse a piece of logic multiple times in a workflow as well as across workflows.

The CompensatableSequence, Compensate, and CompensationHandler Activities

These activities have the following syntax:

  public sealed class CompensatableSequenceActivity : SequenceActivity,    ICompensatableActivity public sealed class CompensateActivity : Activity, IPropertyValueProvider,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> public sealed class CompensationHandlerActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

These activities are commonly used together to provide the functionality for long-running transactions. Long-running transactions are not ACID transactions, which are the archetypal transactions most developers correlate with relational databases. Rather, a long-running transaction is just a chunk of logic that has an associated chunk of undo or recover logic. The classic example is online travel reservations.

If you book a trip on a travel website that includes airfare, hotel, and a rental car, these bookings likely occur in separate back-end transactions - meaning that the website books the flight, the hotel, and then the car with separate companies. However, if one of these booking fails, none of them should go through. However, because each of the pieces of work occurs with a different company and a different system, a traditional transaction is not easy to implement, if not impossible.

Therefore, some compensation logic needs to be implemented to make sure everything comes out in a valid state at the end of the day. The program flow should go something like this:

  • Book the flight.

  • Book the hotel. If something goes wrong, cancel the flight and then stop.

  • Book the car. If something goes wrong, cancel the flight and hotel and then stop.

It is this type of scenario where the CompensatableSequence and Compensate activities come into play. Because the CompensatableSequenceActivity class inherits from SequenceActivity, it can contain any number of child activities that execute in order. What makes this activity special is that it implements the ICompensatableActivity interface. Activities that implement this interface can be compensated.

That is, they have a designated sequence of activities that can implement the recovering logic if something goes wrong, even if the CompensatableSequence activity has finished executing and/or the workflow has been persisted and reloaded many times. The sequence of recovering logic is implemented by the CompensationHandler activity. You cannot directly add this activity to a workflow from the Visual Studio Toolbox; instead, it is automatically available in a separate activity view on each ICompensatable Activity.

You initiate the compensation logic by setting the TargetActivityName property of the Compensate activity. The TargetActivityName must point to an ICompensatableActivity that already exists in the workflow. Another requirement of this activity is that you must use it inside a CompensationHandler, CancellationHandler, or FaultHandler activity, because these three activities are generally where things might go wrong and require compensation of another sequence of logic.

The CompensatableTransactionScope and TransactionScope Activities

These activities have the following syntax:

  public sealed class CompensatableTransactionScopeActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs>,    ICompensatableActivity public sealed class TransactionScopeActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

Both of these activities implement the same execution logic except for one notable difference, which is covered in a moment. First, you need to understand what these activities were built to do. In .NET 2.0, which was released in October 2005, the System.Transactions namespace was introduced in the Base Class Library. The classes in this namespace, namely Transaction and TransactionScope (not to be confused with the TransactionScope activity), support the ability to implement automatically rolled-back transactions if something goes wrong.

Although .NET transactions are not necessarily related to Windows Workflow Foundation, you should have at least a basic understanding of how these classes work when you’re using the CompensatableTransactionScope and TransactionScope activities. Here’s a simple code sample:

  // start a new transaction scope using (TransactionScope tScope = new TransactionScope()) {     SqlConnection db1;     SqlConnection db2;     try     {         // open database 1 and do some stuff         db1 = new SqlConnection("the connection string for DB1");         SqlCommand com1 = new SqlCommand("some SQL", db1);         db1.Open();         com1.ExecuteNonQuery();         // open database 2 and do some stuff         db2 = new SqlConnection("the connection string for DB2");         SqlCommand com2 = new SqlCommand("some other SQL", db2);         db2.Open();         com2.ExecuteNonQuery();     }     finally     {         // make sure both connections are closed         if (db1 != null && db1.State != ConnectionState.Closed)             db1.Close();         if (db2 != null && db2.State != ConnectionState.Closed)             db2.Close();     }     // Complete the transaction; this performs a commit.     // Because the exception is not handled in the try block above,     // this line will not be called if something goes wrong     tScope.Complete(); } 

If you’ve ever done database programming in .NET, the code wrapped in the using statement should look very familiar. Basically, there is a bunch of database access code (code that could easily break) wrapped inside an active TransactionScope object. When you structure your code in this manner, both of the database commands participate in a single transaction that either commits or rolls back everything that happened in either database. You get this behavior essentially for free from a coding standpoint. This is because the database access classes check to see if there is an active transaction scope, and if there is, they both use it to maintain integrity.

Both the CompensatableTransactionScope and TransactionScope activities use this concept to implement their behavior. Therefore, any logic implemented in either of these activities is automatically rolled back if something goes wrong during initial execution. This behavior follows the properties of an ACID transaction. After this, the two activities differ.

The CompensatableTransactionScope activity has the added trait of enabling you to compensate for long-running transactions. Therefore, you can think of the CompensatableTransactionScope activity as a hybrid between the TransactionScope activity and the CompensatableSequence activity (introduced in the previous section). With the CompensatableTransactionScope activity, you have two opportunities to make things right in a bad situation: when the activity is initially executing and it rolls back the ACID transaction, and when something goes wrong down the road and the manual compensation logic that was implemented is called. The manual compensation logic does not provide the same outcome as the ACID rollback, but it does provide an opportunity to put things in a stable state.

You don’t need to understand everything related to .NET transactions to use these activities, but you should have a broad understanding of what is going on behind the scenes. You can find many good resources dedicated to this topic by searching the web for System.Transactions.

The ConditionedActivityGroup Activity

The syntax of the ConditionedActivityGroup activity (or CAG) is as follows:

  public sealed class ConditionedActivityGroup : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

This is a composite activity that executes its child activities based on their conditions and does so until an overall condition is true.

Consider, for example, a CAG activity that has two child activities. The first child activity has a WhenCondition that executes as long as a countervariable is less than 5. The second child activity does not have a WhenCondition set; therefore, it executes only once. In addition, the CAG activity itself has an UntilCondition that checks another variable for a specific value indicating that the CAG activity execution should end. You can set this indicator variable during the first child activity’s execution when an abnormal situation arises. So the first child activity executes either five times or until the indicator variable is set to a specific value, and the second child activity still executes only once.

The Delay Activity

The syntax of the Delay activity is as follows:

  public sealed class DelayActivity : Activity, IEventActivity,    IActivityEventListener<QueueEventArgs> 

You can use the Delay activity in long-running workflows when waiting for an outside entity to complete its work. A typical scenario is when an e-mail asking for an interaction with the business process is sent to a person involved in the workflow. When the e-mail is sent, the workflow is essentially idle until the outside entity performs his or her part. In this case, you could use the Delay activity in a Listen activity (discussed later) along with another activity that is waiting for the response from the outside entity. You can define the actions to be taken if the Delay activity times out before the person performs his or her part in the process. For example, you could define a loop that resends the e-mail three times and then escalates the issue to a manager.

The most important property on the Delay activity is TimeoutDuration, which is of type System.TimeSpan. You can set this property to a static value during design time or at runtime by using the InitializeTimeoutDuration event that is called right before TimeoutDuration needs to be set. The format that this property uses is the same as the TimeSpan.Parse method. For example, the string 1.12:00:00 represents one day, twelve hours, zero minutes, and zero seconds.

The Delay activity implements the IEventActivity interface, which is the same interface used by the HandleExternalEvent activity. This interface defines the functionality necessary for an activity to raise events to the workflow. Hence, the Delay activity enables you to raise an event to the workflow when it reaches its maximum wait time.

The EventDriven Activity

The syntax of the EventDriven activity is as follows:

  public sealed class EventDrivenActivity : SequenceActivity 

You can use this activity across the two workflow types: sequential and state machine. Like the Sequence activity, the EventDriven activity executes child activities in a certain order. Unlike the Sequence activity, however, the EventDriven activity’s execution is kicked off by an event being raised. This event is defined by the first child of the EventDriven activity, which must be an activity that implements IEventActivity, such as HandleExternalEvent or Delay.

In a sequential workflow, you can use the EventDriven activity in combination with other activities. For example, you can use it in the Events view of the EventHandlingScope activity (which is discussed next). In this view, you can use any number of EventDriven activities to define multiple sets of activities for sequential execution.

You can also use the EventDriven activity in state-machine workflows. In fact, the EventDriven activity is at the heart of what makes state-machine workflows function. Instances of the EventDriven activity can sit in State activities and are executed when configured events are raised. However, you must consider several things before using the EventDriven activity within a state-machine workflow. First, only one activity that implements IEventActivity can be contained within an EventDriven activity. In addition, to prevent deadlocks in the workflow runtime, this IEventActivity activity must be the first child of the EventDriven activity.

Chapter 10 discusses state-machine workflows in more detail.

The EventHandlingScope and EventHandlers Activities

These activities have the following syntax:

  public sealed class EventHandlingScopeActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> public sealed class EventHandlersActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

On its surface, the EventHandlingScope activity is a sequential activity, meaning that it executes a string of defined activities in a specific order. However, there is more to it than that. The EventHandlingScope activity also has a view that shows an EventHandlers activity.

The EventHandlers activity can have any number of EventDriven activities as children, and as you already know, the EventDriven activity generally has something like a HandleExternalEvent activity as its first child.

So here’s the catch: Any or all of the EventDriven activities contained within the EventHandlers activity might execute if, and only if, the main sequence activity of the EventHandlingScope activity has not finished. Furthermore, any of the EventDriven activities might execute multiple times, but again, only if the main sequence activity has not completed.

The FaultHandler and FaultHandlers Activities

These activities have the following syntax:

  public sealed class FaultHandlersActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> public sealed class FaultHandlerActivity : Sequence, ITypeFilterProvider,    IDynamicPropertyTypeProvider 

The FaultHandler activity can be likened to a catch block in C#. It basically watches for a fault, or exception, of a specified type and executes its child activities if that fault type is caught. Faults correspond to standard .NET exceptions, which are classes that inherit directly or indirectly from System.Exception. Therefore, the FaultHandler activity has a property called FaultType, which you use to specify an exception class. In addition, you use the Fault property to set a member variable of the same type as the FaultType property. This enables you to inspect the exception class after the fault is handled.

The FaultHandlers (notice the s) activity can hold any number of FaultHandler activities and provides a place to set up activities to be executed if a particular fault is caught. Consider Figure 6-1, for example.

image from book
Figure 6-1

In the figure, the Faults view of the workflow shows an instance of a FaultHandlers activity ready for use. In addition, two FaultHandler activities have been added between the left- and right-facing arrowheads. The second FaultHandler activity is selected and configured to catch an exception of type System.Data.SqlClient.SqlException. The Fault property is pointing to a class variable called sqlException in the workflow’s code-beside class. The variable definition is shown in the following code:

  private System.Data.SqlClient.SqlException sqlException; 

The HandleExternalEvent Activity

The syntax of the HandleExternalEvent activity is as follows:

  public class HandleExternalEventActivity : Activity, IEventActivity,    IActivityEventListener<QueueEventArgs>, IDynamicPropertyTypeProvider 

The HandleExternalEvent activity is generally used in concert with the CallExternalMethod activity to facilitate communications between a workflow instance and its host. Because this activity implements the IEventActivity interface, it is able to listen for a configured event and execute when that event fires. It uses its InterfaceType and EventName properties to identify the event to listen for on a corresponding communication service. The HandleExternalEvent activity also has a property called ParameterBindings that maps the parameters passed to the event’s event handler to member variables in the workflow.

The HandleExternalEvent activity is also commonly used with the Listen activity. Each branch of a Listen activity takes an activity that implements IEventActivity as its first child. This enables a sequence of other activities to execute an event that is configured on a HandleExternalEvent activity.

The IfElse and IfElseBranch Activities

These activities have the following syntax:

  public sealed class IfElseActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> public sealed class IfElseBranchActivity : SequenceActivity 

The IfElse and IfElseBranch activities enable you to define conditional logic flow, just as you can with logic flow constructs in traditional programming languages. Without the IfElseBranch activity, the IfElse activity is essentially useless.

The IfElse activity acts as a container for one to n IfElseBranch activities. Each branch can hold multiple child activities, which execute in a given order - the standard behavior for a Sequence activity, which the IfElseBranch activity inherits from.

Each IfElseBranch activity has a property called Condition of type ActivityCondition. This property defines a logical condition that must be true for that branch to execute. Every branch in an IfElse activity must have this property set without the last branch (which acts as the else branch). You can define the conditional logic using either of the following methods:

One method is to set the Condition property to an instance of the CodeCondition class. This class exposes an event, also called Condition, that is fired when the IfElseBranch activity’s logic needs to be evaluated. The event is of type EventHandler<ConditionalEventArgs> and passes a ConditionalEventArgs instance to the event handler. The event handler implements the conditional logic and then sets the Result property of ConditionalEventArgs to true or false.

The other method of providing logic to the IfElse activity is to set the Condition property of an IfElseBranch activity to an instance of the RuleConditionReference class. This class acts as a pointer to a rule that exists in the workflow’s rules set.

Chapter 9 discusses rules in detail.

The InvokeWebService Activity

The syntax of the InvokeWebService activity is as follows:

  public sealed class InvokeWebServiceActivity : Activity,    IDynamicPropertyTypeProvider 

This activity enables a workflow to make calls to external web services. Adding this activity to your workflow is similar to adding a web reference in a .NET project. The Add Web Reference dialog box (shown in Figure 6-2) is displayed, where you enter a URL that points to the web service to be called. Then click the Add Reference button.

image from book
Figure 6-2

After you enter the URL and click the Add Reference button, a web service proxy class is generated, and the ProxyClass property of the InvokeWebService activity is set to point to this newly created class. For the activity to be fully configured, you must also set the MethodName property, which specifies the web service method to be called as well as any parameters and return values related to that method.

There is more to the InvokeWebService activity, such as dealing with the issue of ASP.NET sessions and cookies. Chapter 13 covers this issue and more details regarding web services and Windows Workflow Foundation.

The InvokeWorkflow Activity

The syntax of the InvokeWorkflow activity is as follows:

  public sealed class InvokeWorkflowActivity : Activity, ITypeFilterProvider 

You use this activity to asynchronously kick off the execution of another workflow. You point to the Type instance of the workflow to be executed using the TargetWorkflow property. The InvokeWorkflow activity also exposes an event called Invoking, which you can use to prepare parameter variables to be passed to the destination workflow.

Because the InvokeWorkflow activity calls another workflow asynchronously, the activity returns control to the calling workflow before the new workflow’s execution.

The Listen Activity

The syntax of the Listen activity is as follows:

  public sealed class ListenActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

This activity allows a workflow to wait and listen for events without knowing which one will actually fire. The Listen activity can have any number of branches, each of which must have an activity that implements IEventActivity as its first child, the most obvious choices being the HandleExternalEvent and Delay activities.

This activity comes in most handy when you want to tell the workflow to wait for some response from the outside world, but that response could be any number of things. For example, a workflow might be waiting for a response to whether a loan should be approved. In this case, you could have one branch of the Listen activity containing a HandleExternalEvent activity to handle an Approved event, and another branch to handle an event called Rejected. You could even add a third branch with a Delay activity to handle the situation if a response is not provided in a timely fashion.

The Parallel Activity

The syntax of the Parallel activity is as follows:

  public sealed class ParallelActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

This activity enables you to have multiple activities executing independent of one another. You configure the Parallel activity with multiple branches, all of which have a Sequence activity as their first child.

Although the execution of each branch occurs independently of the other branches in a seemingly parallel fashion, this is actually not the case - so the name Parallel is a little deceiving. Because Windows Workflow Foundation runs workflow instances on a single thread, multiple branches cannot run at the same time. Instead, the parallel execution is simulated. The Parallel activity runs the first activity of the first branch, and after that activity’s execution has completed, the first activity of the second branch is run. This process continues until all activities in all branches have been executed.

See Figure 6-3 for an example of how the Parallel activity functions. In this workflow, the doStuffA activity of parallelBranchA is executed first, followed by doSomethingA, then doStuffB, and finally doSomethingB. After all four activities are run, the Parallel activity’s execution is complete.

image from book
Figure 6-3

Although this example illustrates how the Parallel activity works, the order in which activities aree executed is never guaranteed and should not be counted on during runtime.

To illustrate the Parallel activity’s execution model, Figure 6-4 shows a console window with messages printed from each Code activity.

image from book
Figure 6-4

The Policy Activity

The syntax of the Policy activity is as follows:

  public sealed class PolicyActivity : Activity 

You use this activity to evaluate a set of predefined rules. It includes a RuleSetReference property, which is a pointer to the rules set.

Rules are a massive topic, and Chapter 9 is devoted to them. There is also more information about the Policy activity in that chapter.

The Replicator Activity

The syntax of the Replicator activity is as follows:

  public sealed class ReplicatorActivity : CompositeActivity 

This activity creates any number of instances of its single child activity. You can combine this activity with the Sequence activity or any other composite activity to allow multiple children.

The Replicator activity has a collection property called CurrentChildData that dictates how many times the child activity is replicated. You can populate this collection in an event handler for the Initialized event of the Replicator activity.

In addition, the Replicator activity has a property called ExecutionType, which you can set to one of two values in the ExecutionType enumeration. If you set this property to ExecutionType.Sequential, an instance of the child activity is created and executed before any other instances are created and subsequently executed. Conversely, if you set the ExecutionType property to ExecutionType.Parallel, all child activity instances are created first and then executed in a parallel fashion.

In some situations, you might want the execution of child activities to be canceled if a certain condition evaluates to true. In these cases, you can set the UntilCondition property to the desired code or rule condition.

The Sequence Activity

The syntax of the Sequence activity is as follows:

  public class SequenceActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

This is another utility activity. Its functionality is simple and allows the execution of child activities to occur in a defined order. The SequentialWorkflowActivity workflow class derives from SequenceActivity (discussed earlier).

This activity is most commonly used with other activities that allow only one child. For example, you can use the While activity with a Sequence activity to allow multiple children to execute in a loop iteration. In addition, the branches of the Parallel activity require that their sole child be a Sequence activity.

The SetState Activity

The syntax of the SetState activity is as follows:

  public sealed class SetStateActivity : Activity 

As you might imagine, the SetState activity is used with the state-machine workflow type and dictates which state the workflow should enter upon its execution. You can use this activity in the EventDriven, StateInitialization, and IfElse activities, but it must be the last child in each respective activity. The important property of this activity is TargetStateName, which is a string representing the desired subsequent state in the workflow.

Figure 6-5 shows an example of a SetState activity called setTheState. Here, the SetState activity is being used in an EventDriven activity within a workflow state called StateMachineInitialState. After the HandleExternalEvent activity called eventFired executes, the setTheState activity transfers the workflow from the StateMachineInitialState state to the waitingState state. Doing this also draws an arrow from the first to the second state in the main state-machine workflow view.

image from book
Figure 6-5

State-machine workflows are discussed in detail in Chapter 10.

The State Activity

The syntax of the State activity is as follows:

  public class StateActivity : CompositeActivity 

This activity is the heart of the state-machine workflow type. Each State activity represents a discrete status that a state-machine workflow can be in. The State activity doesn’t really do anything - it is a container for all functionality that exists within that state. The EventDriven, StateInitialization, and StateFinalization activities can be children of a State activity, and all workflow logic is implemented in any of these three activities.

The StateFinalization and StateInitialization Activities

These activities have the following syntax:

  public sealed class StateFinalizationActivity : SequenceActivity public sealed class StateInitializationActivity : SequenceActivity 

You can use the StateFinalization and StateInitialization activities to perform any kind of logic when a state-machine workflow’s state is entered or exited. A State activity can contain zero or one of both of these activities. Because both of these activities inherit from SequenceActivity, child activities are executed in the order specified during workflow design.

All aspects of the state-machine workflow type are covered in Chapter 10.

The Suspend Activity

The syntax of the Suspend activity is as follows:

  public sealed class SuspendActivity : Activity 

You use this activity to pause a workflow instance’s execution - generally, when an error occurs. The Suspend activity has a System.String property called Error that you can use to provide an error message describing what happened that caused the workflow to suspend itself.

When this activity is executed, the WorkflowRuntime’s WorkflowSuspended event is raised in the host, which then passes an instance of WorkflowSuspendedEventArgs to the event handler. This event arguments class has a property called Reason that contains a copy of the SuspectActivity.Error property.

You can write code to enable the workflow to restart after the issue that caused the suspension is resolved. To restart a suspended workflow instance, simply call the WorkflowInstance.Resume method from the host.

The SynchronizationScope Activity

The syntax of the SynchronizationScope activity is as follows:

  public sealed class SynchronizationScopeActivity : Sequence 

You can use this activity to synchronize the execution of a workflow when activities such as the Parallel activity execute children at the same time. Instead of simultaneously executing multiple activities, you can configure SynchronizationScope so that activities are executed separately, one after another.

As you learned previously, the Parallel activity enables you to have any number of branches, each containing Sequence activities, which execute pseudosimultaneously. However, there may be a workflow in which you want one branch to finish before the next starts execution. This is when you would use SynchronizationScope activities as children to the applicable Sequence activities. However, the simple act of adding a couple of SynchronizationScope activities to your workflow does not automatically create an isolated execution scope. You must set one or more of these activities’ SynchronizationHandles properties to matching values. You can set these values in the Visual Studio’s properties window.

To illustrate how this activity affects parallel execution, consider the example given in the Parallel activity section. If the activities in both parallel branches were wrapped in SynchronizationScope activities, and both SynchronizationScope activities had their SynchronizationHandles properties set to the same value, the execution order would change from this

  • doStuffA

  • doSomethingA

  • doStuffB

  • doSomethingB

to this:

  • doStuffA

  • doStuffB

  • doSomethingA

  • doSomethingB

The Terminate Activity

The syntax of the Terminate activity is as follows:

  public sealed class TerminateActivity : Activity 

As with the Suspend activity, when the Terminate activity is executed, the workflow instance’s execution is interrupted. Unlike the Suspend activity, however, when you use the Terminate activity, the workflow is permanently terminated, and you cannot restart it at a later time.

When this activity is run, the WorkflowTerminated event of WorkflowRuntime is executed on the workflow host. This event passes an instance of WorkflowTerminatedEventArgs to the event handler that has a property called Exception. This property is of type System.Exception and allows the host to inspect the exception that caused the workflow to be terminated. Because the workflow instance is permanently terminated, all queued work items are deleted because they cannot be executed at a later time.

The Throw Activity

The syntax of the Throw activity is as follows:

  public sealed class ThrowActivity : Activity, ITypeFilterProvider,    IDynamicPropertyTypeProvider 

This activity is similar to the throw keyword in C#. A .NET exception is tied to the Throw activity through its Fault property, which is of type System.Exception. When the Throw activity is executed, it calls a throw command on the exception instance specified in the Fault property. The exception is thrown outside the bounds of the workflow instance, to the workflow host. In addition, the workflow is terminated, and the WorkflowTerminated event of the WorkflowRuntime class is raised to the host.

The WebServiceFault Activity

The syntax of the WebServiceFault activity is as follows:

  public sealed class WebServiceFaultActivity : Activity 

The execution of this activity corresponds to sending a web service fault to a client during a request-response operation. You use this activity with the WebServiceInput activity, which is discussed next.

The WebServiceInput Activity

The syntax of the WebServiceInput activity is as follows:

  public sealed class WebServiceInputActivity : Activity, IEventActivity,    IActivityEventListener<QueueEventArgs>, IDynamicPropertyTypeProvider 

You use this activity to expose a workflow as a web service. It represents the entry point of a web service method call. The WebServiceInput activity uses an interface to represent a method that exists on a web service. To configure the activity for this, you use the InterfaceType and MethodName properties.

In addition, the WebServiceInput activity has a Boolean property called IsActivating, which specifies whether the activity should create a new instance of the workflow and start it when the configured method is called. When this property is set to true, the WebServiceInput activity must be the first child of the workflow. Conversely, if the WebServiceInput activity is the first child, the IsActivating property must be set to true.

When using this activity, you must have a corresponding WebServiceOutput activity (discussed next). Chapter 14 discusses web services and how they affect Windows Workflow Foundation.

The WebServiceOutput Activity

The syntax of the WebServiceOutput activity is as follows:

  public sealed class WebServiceOutputActivity : Activity,    IDynamicPropertyTypeProvider 

You use the WebServiceOutput activity in conjunction with the WebServiceInput activity to expose workflows as web services. The WebServiceInput activity acts as a web service method’s entry into a workflow, and the WebServiceOutput activity prepares values to be passed back to the calling application and acts as the logical exit point of the web service method.

A WebServiceOutput activity must follow a WebServiceInput activity. However, it does not have to directly follow the input activity - there can be other activities between the two. Also, just because the WebServiceOutput activity is the logical exit point for a web service method does not mean that it has to be the last child in a workflow. Other activities can follow the WebServiceOutput activity, but they do not have any affect on the return values of the web service method.

In addition, the WebServiceOutput activity must have its InputActivityName property set to the corresponding WebServiceInput activity.

The While Activity

The syntax of the While activity is as follows:

  public sealed class WhileActivity : CompositeActivity,    IActivityEventListener<ActivityExecutionStatusChangedEventArgs> 

This is a logic flow activity with the same functionality as the while loop construct in C#. Like the IfElseBranch activity, which uses its Condition property to determine whether the branch executes, the While activity also has a Condition property. Also like the IfElseBranch activity, the While activity’s Condition property is of type ActivityCondition and can take an instance of CodeCondition or RuleConditionReference.

The While activity can contain only one child activity. To overcome this limitation, just use the Sequence activity as the sole child activity. You can then drop as many activities in the Sequence activity as you wish. Figure 6-6 shows an example of this.

image from book
Figure 6-6



Professional Windows Workflow Foundation
Professional Windows Workflow Foundation
ISBN: 0470053860
EAN: 2147483647
Year: 2004
Pages: 118
Authors: Todd Kitta

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net