Chapter 15. Windows Workflow Foundation

Part V focuses on developing workflows and orchestrating business processes within Microsoft SharePoint 2013. First, in this chapter, you will learn about the architecture, capabilities, and functionality of Microsoft Windows Workflow Foundation (WF) 4.5, which serves as the basis of the new workflow engine of SharePoint 2013. To master the workflow engine of SharePoint 2013, you first need to understand the workflow engine of WF 4.5 itself. While subsequent chapters of Part V will cover workflows for SharePoint, this chapter delves into WF 4.5 alone.

Architecture of Windows Workflow Foundation 4.5

The latest version of the workflow engine from Microsoft, WF 4.5, is a rich set of libraries, types, and tools for creating custom workflow-based software solutions and is implemented with Microsoft .NET Framework 4.5. WF 4.5 is not a ready-to-use software or an application server available out of the box. With WF 4.5, you can’t do anything unless you write custom code on top of the WF 4.5 engine. WF 4.5 is a tool for developers, not a software application for end users. You, as a developer, can create software applications providing workflow-based functionality using .NET 4.5 and WF 4.5.

Note

To learn how SharePoint 2013 takes advantage of WF 4.5 to provide workflow-based capabilities to end users, see Chapter 16

In WF 4.5, every workflow is made of a set of activities or at least a single activity. An activity is the smallest unit of execution for a workflow and can be considered a single step of a workflow. Activities can be created by developers, or can be taken from the list of activities already available out of the box. Typically, a real workflow solution is made of activities available out of the box as well as custom developed ones. Whenever you need to implement a software application that uses WF 4.5, you should analyze the requirements of the target solution and define the custom activities necessary to implement that solution. Regardless of the number and type of custom activities you will develop, every workflow definition will be made of markup code defined using a syntax called XAML. When you run a workflow instance, you load the workflow definition, provide some input arguments, and allocate a thread for executing that workflow instance. Internally, the workflow engine will run every workflow instance with a maximum of one thread at a time.

WF 4.5 is based on the architecture shown in Figure 15-1. You can think of every application that uses WF 4.5 as a host application. Host applications access the WF runtime for loading and executing workflow instances, as well as the WCF (Windows Communication Foundation) runtime for communicating between the workflow instances and the outside. Every workflow instance can be persisted onto a dedicated persistence storage, and can also be monitored using out-of-the-box tools.

With Microsoft Visual Studio 2012, you can not only define workflows while developing custom solutions, but also use the native libraries of WF 4.5 to create custom workflow designers of your own. You can then include these workflow designers in your custom applications.

On the hosting side, you can also host and run workflow instances within Internet Information Services (IIS) and manage those instances using IIS management tools. You can also use Windows Server AppFabric, which provides some useful monitoring and management tools that extend the native capabilities of IIS.

A diagram illustrating the architecture of WF 4.5. At the base is a host application, which represents the software solution that effectively hosts the workflow engine and that runs in a host process. On the next level up, to run workflow instances, you need to have the WF runtime, and sometimes also the WCF runtime for communicating with external systems or with other workflows. Every running workflow instance uses some infrastructural services for persistence, storage, and monitoring. Moreover, every workflow uses a rich set of native activities, and typically uses some custom activities (the top level of the host process). Above the host process can be supporting tools like Windows Server AppFabric, IIS and its management tools, Visual Studio 2012, and custom workflow designers.

Figure 15-1. A simplified schema showing the architecture of a system with externalized authentication.

When you create a new workflow definition, you can choose between three workflow models that are available out of the box:

  • Sequence. Represents a sequential workflow in which you define an explicit entry point (start) and a well-known exit point (end). The workflow instances will be executed from the start to the end, stepping through multiple steps and following some branches, without the capability to step backward through the flow. The only way to step backward in a sequential workflow is to define multiple nested loops, but doing so would result in overly complex and difficult-to-manage workflows.

  • Flowchart. Defines a flow that behaves like a flow diagram; it can be traversed from start to finish, and specific conditions and rules can return the flow to previously completed steps.

  • State machine. Defines a state machine flow, which is made of a set of states and rules to transfer the flow. It is the most suitable solution for implementing human-interactive flows, because end-user behavior is unpredictable and nondeterministic.

Those are just basic examples of flow definitions. In reality, you can mix the three models within a single workflow definition. For example, you can create a flowchart workflow that internally is made of some sequences or state machines. You even can create workflow shapes of your own and plug them into the native infrastructure; however, flowcharts, sequences, and state machines can satisfy almost every need.

The XAML code of a sample sequential workflow contains an example excerpt of XAML defining a sequential workflow that provides the typical “Hello world” message.

Aside from some infrastructural content, the real workflow definition is highlighted in bold and simply declares a sequence made of one activity of type WriteLine, which will write to the console window a welcome message with a text value of Hello world! Figure 15-2 shows the listing’s graphical representation in the workflow designer available in Visual Studio 2012.

A screen shot illustrating the workflow designer provided by Visual Studio 2012, in which a very simple workflow that welcomes end users is being designed. The main content of the screen presents a whiteboard designer with a sequence containing a WriteLine box, which is an instance of a WriteLine activity properly configured to write a welcome message.

Figure 15-2. The graphical designer of Visual Studio 2012 presenting a sample workflow definition.

Furthermore, consider that with WF 4.5 you can also define a workflow simply by writing a few lines of code, aggregating instances of activities in an object graph defined as Microsoft C# or Visual Basic .NET source code. A sample sequential workflow only based on C# code shows a code excerpt of a C#-based workflow.

Your first workflow project

To better understand how to define a workflow, try creating an extremely simple workflow definition corresponding to a flow for selecting a vacation destination. Imagine that you want to create, using WF 4.5, the workflow depicted as a flow diagram in Figure 15-3.

A flow diagram presenting a sequential workflow that greets the user and evaluates a destination country for spending a vacation. Depending on the provided target country, it will suggest one specific place to the user, and will then end.

Figure 15-3. A flow diagram depicting a sample workflow outline.

To represent this workflow using WF 4.5, you can start by creating a sample Workflow project in Visual Studio 2012. Under the list of available project templates, you can find a group of workflow projects, where you can create one of the following:

  • Activity Designer Library. Represents a project template for creating a custom designer for a custom set of activities (discussed in Chapter 18).

  • Activity Library. Represents a project template for creating a new set of custom activities (discussed later in this chapter and in Chapter 18).

  • WCF Workflow Service Application. Defines a project for hosting a workflow service, which will be published by a WorkflowServiceHost object. This topic will not be covered in detail in this book, because it is out of the scope of SharePoint 2013 workflows.

  • Workflow Console Application. Defines workflows that will run in the console environment of a Windows machine. It is a good option for practicing with WF 4.5 and for creating sample workflows.

For the example, start with a Workflow Console Application project template. You will be prompted with a blank design surface, and with a rich toolbox of activities on the left side of your screen. Figure 15-4 shows the Visual Studio 2012 interface just after the new project is created.

A screen shot illustrating the outline of a sample workflow project in Visual Studio 2012, just after it has been created. On the left is a toolbox rich with activities. Some of them are related to WF 4.5 in general; others are related to SharePoint. On the right is the typical Solution Explorer of Visual Studio 2012. In the middle is the workflow design surface.

Figure 15-4. The outline of the sample workflow project in Visual Studio 2012.

To start designing your flow, drag an activity from the toolbox and drop it onto the workflow design surface. The following are the available groups of activities:

  • Control Flow. Activities for defining and controlling the flow of your processes. For example, in this group you can find activities like DoWhile, ForEach, If, Parallel, and so on.

  • Flowchart. Activities for defining a flowchart-based workflow. Such activities include FlowChart, FlowDecision, and FlowSwitch.

  • State Machine. Activities for defining state machine workflows. These activities include StateMachine, State, and FinalState.

  • Messaging. Activities for communicating with external systems, using SOAP (Simple Object Access Protocol), WCF, REST (Representational State Transfer) and HTTP, and so on. This is one of the richest groups of activities.

  • Runtime. Activities for persisting workflow status, terminating a workflow instance, executing a piece of flow without any persistence, and so on. These are the very core activities of WF 4.5.

  • Primitives. Activities to invoke external code, assign a value to a variable, wait for a delay, and perform other fundamental tasks.

  • Transaction. Activities like TransactionScope, CompensableActivity, Compensate, and CancellationScope, which are related to transactional tasks.

  • Collection. Activities for managing collections of items and variables. You can find activities for adding, removing, retrieving, and checking for the existence of items in a collection, and more.

  • Error Handling. Activities for handling errors, such as TryCatch, Throw, and Rethrow.

  • Migration. Activities to interoperate with previous versions of WF.

  • DynamicValue. Activities for managing dynamic values and types. For example, these include activities for managing JavaScript Object Notation (JSON) and OData content.

While working in an environment configured for developing SharePoint and Microsoft Office solutions, you will also find many other categories of activities, all with SP in their name. Chapter 17 will discuss them. This chapter, however, focuses on the standard and basic workflow engine of WF 4.5.

To create the workflow illustrated in Figure 15-3, you need to design a FlowChart activity. For instance, specify a value of Vacation Flowchart for its DisplayName property. Every FlowChart activity starts with a predefined startup point. Add a WriteLine activity to the flowchart and connect it to the green startup symbol. By clicking in the body of the WriteLine activity, you will be able to provide text to display on the console as a greeting message. Notice that here you can write any C# or Visual Basic expression. In fact, one of the main capabilities of the designer for WF 4.5 is the ability to configure activities using dynamic and code-based expressions. For the sake of simplicity, imagine the user provides the name of the destination to get the country as an input argument at the workflow startup. In a real workflow, you would probably use a custom activity for querying the user and for validating the provided input.

To declare an argument or variable, you can use the workflow designer. In the lower-left corner of the designer in Visual Studio 2012 are three tabs: Variables, Arguments, and Imports. The Variable tab enables you to define variables for holding values during execution of workflow instances. Variables can be scoped to define their lifetime and availability. The Arguments tab allows defining properties, input, output, or both input/output arguments that can be used to configure the workflow instances. With the Imports tab, you can define the assemblies that you want to reference in the code running within the workflow you are defining. To accept the TargetCountry argument, click the Arguments tab, and declare an input argument with name TargetCountry and type String.

Then design a FlowSwitch<T> activity with a value of System.String for the T to disambiguate. Connect the FlowSwitch<T> activity with the WriteLine activity you defined before and determine the behavior of the workflow, based on the content of the TargetCountry argument. To achieve this result, configure the Expression property of the FlowSwitch<T> activity in order to map it to the TargetCountry argument. Then, for the sake of simplicity, imagine that you want to use a WriteLine activity for each of the user’s choices. According to the diagram in Figure 15-3, if the user provides a value of Italy for the TargetCountry argument, the workflow will suggest going to Venice; if the user provides a value of Germany, then the workflow will suggest visiting Munich; lastly, if the user provides any other value, the workflow will simply write “Other.” Figure 15-5 illustrates the resulting flowchart definition.

A screen shot illustrating the sample workflow designed in Visual Studio 2012. The design surface area shows the flowchart with its starting point, and a FlowSwitch<T> activity with three possible outcomes: Italy, Germany, and any other country.

Figure 15-5. Outline of the sample workflow project in Visual Studio 2012.

To start debugging your new workflow definition, right-click the first WriteLine activity in the designer and select the Insert Breakpoint menu item from the Breakpoint menu. Now you can simply start playing the workflow in Visual Studio 2012 by pressing F5.

By default, the workflow instance starts with an empty value for the TargetCountry argument, and the flow will go through the default path (Other). You can configure a default value for this argument through the Arguments tab of the designer, or you can start the workflow providing an argument from outside the flow. In the next section, you will learn how to start a workflow providing some input arguments.

Hosting and execution

Out of the box, you have three available options for hosting and executing a workflow instance:

  • The WorkflowInvoker class

  • The WorkflowApplication class

  • The WorkflowServiceHost class

The WorkflowInvoker class executes a single workflow instance using a single-threaded and synchronous model. The WorkflowInvoker execution engine assumes you want to execute a workflow instance that will run for a short time, without any kind of persistence storage. This option is suitable for quick and small workflows, which in general are simple, and which do not really need to be scalable, highly available, or asynchronous. The C# code excerpt in Executing a workflow instance through a WorkflowInvoker object uses a WorkflowInvoker object to host and execute a workflow instance, based on the chapter’s example workflow.

When using a WorkflowInvoker object, you can also include input arguments, within a variable of type Dictionary<String, Object>. In the code sample, the arguments provide a value for the TargetCountry argument.

Alternately, you can use an instance of the WorkflowApplication class, which allows hosting and executing a single workflow instance within an independent, scalable, asynchronous, and persistable runtime engine. In fact, the WorkflowApplication class internally uses a dedicated scheduler based on a thread pool. The scheduler can execute a workflow instance for a long time, even persisting its status into a back-end persistence storage if it becomes idle. The C# code excerpt in Executing a workflow instance using a WorkflowApplication object executes a workflow instance using a WorkflowApplication object, but is very basic. Later in this chapter, you will more thoroughly investigate workflow persistence.

Notice that in Executing a workflow instance using a WorkflowApplication object, the code waits for the workflow execution using an object of type ManualResetEvent. The workflow instance will be executed asynchronously, and the hosting application will have to wait for the background task to complete. Furthermore, while hosting a workflow instance within a WorkflowApplication object, you have the capability to suspend, unload, resume, or terminate a running workflow instance.

If the workflow you are implementing has to be published as a service, you have one last execution option. You can empower the WorkflowServiceHost class, which provides a hosting and execution infrastructure that internally uses the WCF engine and allows publishing of a workflow service. Such workflows can be defined within a web application and can be published using IIS or a custom self-hosting application. Not every workflow definition can be hosted within a WorkflowServiceHost object. To host a workflow definition as a workflow service, you need to design the workflow accordingly and use some specific activities that internally implement a WCF service contract.

Custom activities

As you know, every workflow definition is made of one or more activities. From a developer perspective, a workflow activity is just a piece of markup that aggregates already existing activities or is a custom class implementation. Using the Visual Studio 2012 workflow designer, you can easily implement a custom activity. To do so, open the chapter’s sample project and add a new workflow project of type Activity Library.

In the new project, you will find a new project item with extension .xaml; this is an XML-based file that you will be able to design using the classic workflow designer and the toolbox of available out-of-the-box activities. Here, you can design a kind of subworkflow that you will be able to reuse many times in your own workflow definitions. However, this file can aggregate existing activities only, so its main purpose is to reuse existing elements, rather than to create completely new activities from scratch.

In a real business workflow solution, you will probably need to write some code to implement real activities from scratch. From an object-orientation viewpoint, a custom activity is just a class that inherits from the base class System.Activities.Activity or from one of the other types inheriting from that base class. Figure 15-6 displays the full hierarchy of types available for creating code-based activities.

A diagram showing that every custom code-based activity inherits directly or indirectly from the Activity base class. There are many other base types you can inherit from, depending on the type of custom activity you want to implement.

Figure 15-6. The hierarchy of types available for creating code-based custom activities.

For example, depending on the type of activity you want to implement, you can inherit from one of many available base classes, including the following:

  • CodeActivity. This is the base class to inherit from for creating a synchronous custom activity that provides some functionality implementing a code-based method called Execute, without necessarily providing a result.

  • AsynCodeActivity. This can be inherited to implement an asynchronous activity that can be used to execute code adhering to the asynchronous code execution pattern available in .NET and based on the Begin/End{MethodName} pair of methods. This kind of base class does not return a result value.

  • NativeActivity. This is the base class to inherit from for creating any kind of activity and can interact with the WF 4.5 runtime engine at any level. This base class does not return any result.

  • CodeActivity<TResult>. This can be inherited to implement a code-based activity that will provide a result of type TResult.

  • AsynCodeActivity<TResult>. This is the counterpart of the AsyncCodeActivity, and returns a result value of type TResult.

  • NativeActivity<TResult>. This is the same as the NativeActivity, but activities inheriting from this type will provide a result of type TResult.

In Figure 15-6, there are also some other types available, such as DynamicActivity and DynamicActivity<TResult>. These are sealed classes that are useful for creating custom activities and workflow instances directly in code, but not for creating custom activity types.

Now, think again about the simple vacation workflow example. In Figure 15-3, the workflow definition got the value of the TargetCountry argument from the list of input arguments of the workflow. A better option, however, is to include within the workflow definition some logic that queries the user for the target country, and then to provide some validation rules in the same workflow. To add this custom querying activity (call it ReadLineActivity), you first need to inherit from the CodeActivity<TResult> base class, because you will use some custom code to query the user. The result of type TResult will be a System.String and provide the user-specified target country to the workflow. A sample C# code excerpt implementing a custom ReadLineActivity implements such a custom activity.

As you can see, the simple implementation reads a line from the console and returns the read value through the return value of the Execute method, which overrides the corresponding method of the CodeActivity<String> base class. Moreover, the Execute method receives an argument of type CodeActivityContext, which provides the current request context and which will be used later. Now, build the class library project, and open the workflow designer of the VacationWorkflow definition. Notice the new activity is waiting in the toolbox, ready to be inserted in the workflow definition.

After inserting the new activity, you can configure it. In the property grid of the designer, the custom activity provides a Result property. Delete the TargetCountry argument from the Arguments tab, and define a new TargetCountry variable of type System.String on the Variables tab of the workflow designer. Configure the Result property of the custom ReadLineActivity to return the read value into the TargetCountry variable. Figure 15-7 shows the new outline of the vacation workflow.

A screen shot depicting the workflow designer with the ReadLineActivity in place. It shows the custom activity in the toolbox, the activity instance on the design surface, the TargetCountry variable on the Variables tab, and the Result property of the custom activity, mapped to the TargetCountry variable in the property grid.

Figure 15-7. The workflow designer with the custom ReadLineActivity in place.

When defining custom activities, you not only provide result values, often you also need to accept configuration parameters and input/output arguments. In WF 4.5 custom activities, you can define as many arguments as you want simply by declaring properties of type InArgument<T>, OutArgument<T>, or InOutArgument<T>. As the type names imply, these types represent input, output, and input/output arguments. You can use these types for holding values that will be serialized and deserialized together with the workflow status and that you can use to change the behavior of your custom activities. Imagine that you want to define an input argument for the ReadLineActivity. This argument will be a string message that will prompt the workflow users before asking them for the target country value. A sample C# code excerpt implementing a custom ReadLineActivity with an input argument provides a revised ReadLineActivity implementation.

The property definition is self-explanatory, although the use of the Message property (highlighted in bold) probably is not. You cannot directly access any property of type InArgument<T>, OutArgument<T>, or InOutArgument<T> to read or write its value. On the contrary, you need to employ the Get and Set methods provided for accessing their values in the context of the current activity execution, which is the argument of type CodeActivityContext provided to the Execute method. Any argument defined in this way will be available on the workflow design surface for configuration using an explicit value or an expression.

The custom activity examples based on CodeActivity<TResult> run synchronously within the execution of the target workflow instances. In Chapter 18, you will learn how to implement asynchronous activities using base types like AsyncCodeActivity<TResult> and NativeActivity<TResult>.

Runtime scheduler and workflow process life cycle

From a functional point of view, every workflow instance executes its steps based on a scheduler, which schedules execution of threads and steps during a workflow instance’s lifetime. Technically speaking, the workflow engine of WF 4.5 executes one single activity per time handling a queue of work items that will be executed in a specific order. The queue of work items can be populated by the workflow runtime host (your hosting process), by an activity running in the workflow, or by some external code. As long as the queue of work items has something to do, the workflow scheduler schedules the execution of these work items, once per time in a single-threaded fashion. When the queue of work items is empty or when the currently running work item is handling a background task and there is nothing to do in the meantime, the workflow instance is idle. When a workflow instance is idle or between the executions of work items, you can persist the workflow state. When a workflow instance is idle, you can also unload that instance and reload it later when you have something to do.

Think about document approval workflows. There will be times when an approval workflow has to wait for end users’ approval. It would be useless and dangerous to keep a pending workflow idle in memory just waiting for end users. You would consume resources (RAM and CPU) keeping alive a workflow instance that has nothing to do. Moreover, in the case of a hardware failure or system reboot, you would lose your workflow instance state if you kept it in memory only. On the contrary, if you save the workflow state periodically and you unload idle workflows from memory, you will be able to reload and resume them only when needed, and eventually use a multiserver infrastructure where workflows are loaded and resumed on the server when you have enough resources to manage their execution. Activities provided out of the box by WF 4.5 internally take advantage of this way of working. For activities that you implement, you should consider these issues and create the activities according to the behavior of the runtime scheduler of WF 4.5.

To better understand this topic, change the sample vacation workflow, adding a Delay activity between the ReadLineActivity and the first WriteLine activity. Any Delay activity instance accepts a Duration property, which represents the delay duration as a TimeSpan value. Figure 15-8 shows the new outline of the workflow definition.

A screen shot illustrating the vacation workflow with the Delay activity in place. On the design surface, there is the Delay activity between the first custom ReadLineActivity and the first WriteLine activity. The Delay is configured to wait for 10 seconds.

Figure 15-8. The workflow designer with the custom Delay activity in place.

Running the new workflow outline with a Delay activity contains a revised code excerpt for running the workflow instance using a WorkflowApplication class and intercepting the Idle event.

Running the workflow instance, you will see that, just after providing the target country to the ReadLineActivity instance, the workflow will become idle because of the Delay activity.

Workflow persistence

If a workflow instance is idle and it is running within a WorkflowApplication or a WorkflowServiceHost host, such as SharePoint, you can persist the workflow state as long as you have configured a persistence storage on the back end. Try configuring persistence for the vacation workflow sample running within a WorkflowApplication host. First, you need a properly configured persistence storage. By default, WF 4.5 uses a Microsoft SQL Server custom database for persistence storage. When you install .NET 4.5, the setup package copies onto your file system some SQL files for creating such a persistence database. Under the path %windir%Microsoft.NETFramework64v4.0.30319SQLen, you will find the following files:

  • SqlWorkflowInstanceStoreLogic.sql

  • SqlWorkflowInstanceStoreSchema.sql

  • DropSqlWorkflowInstanceStoreLogic.sql

  • DropSqlWorkflowInstanceStoreSchema.sql

As you can deduce from their names, these files provide the T-SQL commands for creating or deleting the schemas and logic of persistence tables. There are multiple files because sometimes it is useful to create these tables and this logic within an already existing application-specific database, instead of creating a dedicated database. Because you have the source SQL files, you can execute them against any database, and you are free to use them in your own environment, too. These script files target SQL Server 2005 or higher. Run the SqlWorkflowInstanceStoreSchema.sql file first, and then run the SqlWorkflowInstanceStoreLogic.sql file. The first file creates the schemas for the tables, and the second one creates the business logic on top of these schemas.

With your persistence database ready, you next need to reference the assemblies System.Activities.DurableInstancing.dll and System.Runtime.DurableInstancing.dll within your target host application, and you need to change the code in order to use the persistence. A sample C# code excerpt for hosting the vacation workflow with persistence storage configured demonstrates the revised hosting code.

The code for configuring the persistence store is highlighted in bold, as is the PersistableIdle event handler, which will be raised as soon as the workflow instance is idle and ready for persistence. The event handler will be able to return a result of type PersistableIdleAction, which can assume the values None, Persist, or Unload. None does nothing, Persist instructs the WorkflowApplication instance to persist the workflow onto the target store, and Unload instructs the WorkflowApplication instance to persist and unload the workflow instance, to free resources.

Consider that the SqlWorkflowInstanceStore class used in A sample C# code excerpt for hosting the vacation workflow with persistence storage configured is the default implementation of a persistence store service, which is provided out of the box by WF 4.5 and which stores the status of workflows in SQL Server. However, it is just a class inheriting from the InstanceStore abstract class, and you can implement a persistence storage service of your own. For example, on MSDN, you can find a sample for storing workflow data in a custom XML file (see http://msdn.microsoft.com/en-us/library/ee829481.aspx).

If you are wondering what will be saved into the persistence store, you could inspect the table [System.Activities.DurableInstancing].[InstancesTable] created within the persistence storage database. There you will find the serialized workflow instance state, which is not human readable and is mainly made of the following information:

  • The list of work items to execute

  • The list of bookmarks of the current workflow, which will be discussed in Chapter 17

  • Variables, arguments, and all the instance data of the workflow instance

  • Any pending callback, such as a timer

  • Any custom data, because you can extend the persistence of WF 4.5 and provide some custom data to store in the persistence storage

Summary

In this chapter, you investigated the architecture of WF 4.5 and how to take advantage of WF 4.5 in your own software solutions. You also learned how to design a simple workflow, how to create a very basic custom activity, and how the workflow scheduler executes workflow instances and activities. Lastly, you saw how the out-of-the-box persistence storage system works in WF 4.5.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset