This tutorial is the first part of Dispatcher Timer Windows Workflow Foundation tutorial series.
In this article I am going to explain what Windows Workflow Foundation is and what its building blocks are. The contents of this article is mostly based on MSDN articles on WF, the book Professional C# 2012 and .NET 4.5 by Christian Nagel, and my own works and experiences on WF.
WF provides a model to define and execute processes using a set of building blocks called activities. As a workflow executes, it may need to access the outside world, as well as a workflow may need to save and restore its state.
A workflow is constructed from a number of activities, and these activities are executed at runtime. A number of built-in activities can be used for general-purpose work, and you can also create your own custom activities and plug these into the workflow as necessary.
A workflow models a production process as a set of activities applied to work in progress. As such, workflows describe the order of execution and dependency relationships between activities as the work progresses through the model from start to finish, as activities are performed by people or system functions.
Workflow Runtime Engine
Every running workflow instance is created and maintained by an in-process runtime engine that is commonly referred to as the workflow runtime engine. There can be several workflow runtime engines within an application domain, and each instance of the runtime engine can support multiple workflow instances running concurrently.
When a workflow model is compiled, it can be executed inside any Windows process including:
- console applications,
- forms-based applications,
- Windows Services,
- ASP.NET Web sites, and
- Web services.
Because a workflow is hosted in process, a workflow can easily communicate with its host application.
Activities are the elemental unit of a workflow. Everything in a workflow is an activity, including the workflow itself. The term workflow is actually a synonym for a collection of activities. They are added to a workflow programmatically in a manner similar to adding XML DOM child nodes to a root node. When all the activities in a given flow path are finished running, the workflow instance is completed.
There are different types of activities which derived from the base class Activity:
An activity can perform a single action, such as writing a value to a database, or it can be a composite activity and consist of a set of activities.
Activities deriving from CodeActivity and AsyncCodeActivity can do far less with their container compare to NativeActivity. For example, the WriteLine activity needs to write only to the console. Therefore, it doesn’t need access to its runtime environment. A more complex activity might need to schedule other child activities or communicate with other systems, in which case you must derive from NativeActivity to access the full runtime.
Activities have two types of behavior:
- runtime: specifies the actions upon execution.
time: controls the appearance of the activity and its interaction while being displayed within the designer.
The workflow runtime engine uses many services when a workflow instance runs. Windows Workflow Foundation provides default implementations of the runtime services that meet the needs of many types of applications, such as a persistence service, which stores the execution details of a workflow instance in a SQL database. These service components are pluggable, which allows applications to provide these services in ways that are unique to their execution environment. Other types of services used by the runtime engine include scheduling services, transaction services, and tracking services.
Custom services can be created to extend the Windows Workflow Foundation platform by deriving from the base service classes. An example of this would be a persistence service that uses an XML file instead of a database for storage.
Compensation is the act of undoing any actions that were performed by a successfully completed compensable activity because of an exception that occurred elsewhere in a workflow.
Local Communication and Correlation
Host processes can communicate with workflows by exchanging data through custom local communication services. These local communication services implement user-defined interfaces that define methods and events that will be passed between the workflow and the host process.
Host processes can also interact with a specific activity in a specific workflow instance by using a unique ID that is passed between the host process and the workflow as an event argument. This is known as correlation.
Windows Workflow Foundation simplifies the process of creating stateful, long-running, persistent workflow applications. The workflow runtime engine manages workflow execution and enables workflows to remain active for long periods of time and survive application restarts. This durability is a key tenet of Windows Workflow Foundation. It means that workflows can be unloaded from memory while awaiting input and serialized into a persistent store, such as a SQL database or XML file. Whenever the input is received, the workflow runtime engine loads the workflow state information back into memory and continues execution of the workflow.
Windows Workflow Foundation provides the SqlWorkflowPersistenceService that integrates well with Microsoft SQL Server to persist workflow information easily and efficiently. You can also create your own persistence service to store workflow state information anywhere you want by deriving from the WorkflowPersistenceService base class.
Tracking is the ability to specify and capture information about workflow instances and store that information as the instances execute. Windows Workflow Foundation provides the SqlTrackingService, which is a tracking service that uses a SQL database to store the collected tracking information. You can also write your own tracking service to collect and store this information in any format that your application requires.
When a new workflow is created, the tracking service requests a tracking channel to be associated with that workflow. All of the tracking information from the workflow is then sent to this tracking channel.
The tracking service can track three types of events:
- Workflow instance events,
- Activity events, and
- User events.
You can configure the type and amount of information that your service wants to receive for a particular workflow instance or types of workflow by providing a tracking profile.
The tracking framework also provides the ability to extract information about activities or the workflow during an event. If a specific property or field in your activity or workflow needs to be tracked, you can provide this information in the extracts section of the tracking profile, and that information will be extracted during the specified event.
Workflows, activities, and rules can be serialized and deserialized. This enables you to persist them, use them in workflow markup files, and view their properties, fields, and events in a workflow designer.
Windows Workflow Foundation provides default serialization capabilities for standard activities, or you can create your own for custom activities. For example, with a custom activity serializer, you can decide which members are serialized and how they are serialized. This determines if those members are visible or hidden in a workflow designer.
Windows Workflow Foundation enables you to dynamically update your workflow instance and declarative rules during run time. Before activities are scheduled for execution, you can change expected behaviors, flow control, and so on. This ability enables you to modify business processing logic without having to recompile and restart your workflow.
Rules and Conditions
Windows Workflow Foundation can implement business logic as either rules or conditions.
Conditions are used by IfElseBranchActivity, ConditionedActivityGroup, WhileActivity, and ReplicatorActivity activities to control activity execution. Conditions can be expressed as declarative, or defined in code. Declarative conditions are created as code DOM statements in the rules’ XML file. Code-based conditions reference a method in the workflow’s code file that returns its result through the Result property.
Rules, like conditions, are expressed as code DOM statements, and are collected in the rules XML file. Rules include a condition statement and collections of actions that are performed based on the result of the condition. Rules are collected into rule sets, which support both simple sequential execution of rules, and sophisticated forward-chaining of rules. Rule sets are executed by the PolicyActivity activity.
A key advantage of defining your logic with rules and declarative conditions is that they can be modified at run time by doing dynamic updates using workflow changes. In addition, rules let you separate your business logic from a workflow in order to share those rules with other workflows. Finally, defining business logic in rules allows for advanced tools, such as dependency visualization and impact analysis tools, to be built on top of the object model.
Exceptions that occur in activities are handled asynchronously by the workflow runtime engine in a process called fault handling. Exceptions are scheduled in a queue to be handled later. If the exception type matches the one that is handled by a particular FaultHandlerActivity activity, that activity will handle the exception. If the exception cannot be handled, it is bubbled up through parent activities until it ultimately causes the termination of the workflow instance.
Workflow markup, which is based on Extensible Application Markup Language (XAML), enables developers and designers to model business logic declaratively and separate it from lower-level implementation details that are modeled by code-beside files. Because workflows can be modeled declaratively, it is possible to activate a workflow by directly loading a workflow markup file into the workflow runtime engine at run time.
Correlation is the mechanism for relating workflow service messages to each other or to the application instance state, such as a reply to an initial request, or a particular order ID to the persisted state of an order-processing workflow.
Types of Correlation
Correlation can be protocol-based or content-based. Protocol-based correlations use data provided by the message delivery infrastructure to provide the mapping between messages. Messages that are correlated using protocol-based correlation are related to each other using an object in memory, such as a RequestContext, or by a token provided by the transport protocol. Content-based correlations relate messages to each other using application-specified data. Messages that are correlated using content-based correlation are related to each other by some application-defined data in the message, such as a customer number.
Activities that participate in correlation use a CorrelationHandle to tie the messaging activities together. For example, a Send that is used to call a service and a subsequent Receive that is used to receive a callback from the service, share the same CorrelationHandle. This basic pattern is used whether the correlation is content based or protocol based. The correlation handle can be explicitly set on each activity or the activities can be contained in a CorrelationScope activity. Activities contained in a CorrelationScope have their correlation handles managed by the CorrelationScope and do not require the CorrelationHandle to be explicitly set. A CorrelationScope scope provides CorrelationHandle management for a request-reply correlation and one additional correlation type. Workflow services hosted using WorkflowServiceHost have the same default correlation management as the CorrelationScope activity. This default correlation management generally means that in many scenarios, messaging activities in a CorrelationScope or a workflow service do not require their CorrelationHandle set unless multiple messaging activities are in parallel or overlap, such as two Receive activities in parallel, or two Send activities followed by two Receive activities.