Exploring WCF Web Services
TECHNOLOGIES: .NET 3.5 | WCF
Exploring .NET Framework 3.5 Features for Better Workflow and WCF Integration
By Michele Leroux Bustamante
This monthly column explores how to expose workflows as WCF services, and how to consume WCF services from workflows using features introduced with .NET Framework 3.5. If you have questions about migrating your existing ASMX or WSE Web services to WCF, or questions regarding WCF as it relates to Web services, please send them to [email protected]!
Workflow Services were introduced with the release of .NET Framework 3.5 to facilitate better communication between WCF and Windows Workflow Foundation (Workflow or WF). Before this release it was cumbersome at best to start a workflow from a WCF service operation, or to call a WCF service operation from an executing workflow. The term Workflow Services describes a workflow that is exposed as a WCF service and can more easily make calls to other WCF services, thanks to a few new Workflow activities: ReceiveActivity and SendActivity. Visual Studio templates simplify the process of creating a new Workflow Service by generating sample sequential or state machine workflows along with related code and configuration.
In this article I ll explain how Workflow Services can be used to expose workflows as WCF services, and to consume other WCF services and why you would want to leverage these features. I assume you have some basic understanding of Workflow technology, so I won t be introducing you to Workflow concepts.
Why Workflow Services?
Workflow is useful for describing and executing long-running and complex business processes. Typically, we see Workflow technology implemented as part of the middle-tier to automate the flow of messaging between users, applications, and services. For client applications to reach a workflow, it is helpful to expose it as a WCF service either behind the firewall or on the Internet. In a service-oriented system, business functionality is typically exposed through services (for this discussion I ll assume services are implemented in WCF) which means that a workflow is likely to coordinate access to that functionality by calling those services.
Simply put, Workflow Services make it easy to expose a workflow as a WCF service so that client applications can reach it, and make it easy for workflows to call out to WCF services to coordinate access to business logic in a service-oriented system. The value Workflow Services bring to the table is in the removal of overhead to set up communication between WCF and Workflow to accomplish these two scenarios. Under the assumption you are employing workflow in the middle-tier, Workflow Services become a staple item in your application.
Workflow Service Features and Templates
Creating a Workflow Service involves leveraging several .NET Framework 3.5 features, including:
- ReceiveActivity: A new Workflow activity that implements a WCF service operation.
- SendActivity: A new Workflow activity for calling WCF services from an executing workflow instance.
- Context-aware bindings: New WCF bindings specifically for Workflow, which handle workflow instance management between clients and Workflow Services.
- WorkflowServiceHost: A new ServiceHost type that facilitates communication between WCF services and the Workflow Runtime.
For a Workflow developer less familiar with WCF, it might seem daunting to figure out how to create a service contract, select bindings and configure endpoints, configure the ReceiveActivity and SendActivity accordingly, and initialize the correct ServiceHost type. Fortunately, there are two Visual Studio templates to simplify this process: Sequential Workflow Service Library and State Machine Workflow Service Library (see Figure 1). These templates are only shown if you select .NET Framework 3.5 from the Add New Project list.
Figure 1: Workflow Service templates.
Each template creates a new class library project with a sample workflow (sequential or state machine) that has been configured as a Workflow Service as follows:
- Each workflow starts with a ReceiveActivity (shown in Figures 2 and 3).
- The ReceiveActivity is associated with a service operation from a sample WCF service contract. When clients call the operation via proxy, that particular ReceiveActivity is executed.
- The class library includes an app.config file
with a sample
configuration for the Workflow Service.
- The binding used for the Workflow Service endpoint is WSHttpContextBinding, one of the context-aware bindings.
Essentially, the template generates a project with the necessary assembly references, a sample Workflow Service, and the required configuration and set up so you can execute it. To test the service, the class library is set up to use the two WCF test tools released with .NET Framework 3.5, WCF Service Host (WcfSvcHost.exe) and WCF Test Client (WcfTestClient.exe). However, in this article I ll explain how to create your own host and client.
Note: Visit http://msdn.microsoft.com/en-us/library/bb552363.aspx and http://msdn.microsoft.com/en-us/library/bb552364.aspx for more information about the test tools.
For sequential workflows, the ReceiveActivity is the first activity in the workflow (as shown in Figure 2). For state machine workflows, the ReceiveActivity is the first activity contained within an event-driven activity (as shown in Figure 3). Both sample workflows created by the template support clients calling a WCF service operation to initialize the workflow, because the ReceiveActivity is configured to support workflow initialization.
Figure 2: Sequential Workflow Service template results.
Figure 3: State machine Workflow Service template results.
It is still possible to create Workflow Services without the help of a Workflow Service template. You can add new sequential or state machine workflows to a class library project and manually add the ReceiveActivity, create the WCF service contract using dialogs provided, and add the required WCF configuration settings for the Workflow Service endpoint.
The most common use for Workflow Services is to expose a workflow as a WCF service. The main benefit to the developer is that they no longer have to manually initialize the Workflow Runtime or workflow instance from a WCF service operation. Instead, the Workflow Service directly exposes a WCF service operation via ReceiveActivity. This activity represents the implementation of a WCF service operation.
Consider the Workflow Service shown in Figure 4. This Workflow Service exposes three ReceiveActivity instances implementing three WCF service operations: ReceiveOperation1, ReceiveOperation2, and ReceiveOperation3. ReceiveOperation1 kicks off the workflow; ReceiveOperation2 and ReceiveOperation3 can be called only after the workflow has started. Once a client calls one of the latter two operations, the workflow is completed.
Figure 4: A Workflow Service with multiple ReceiveActivity instances.
Each ReceiveActivity has a number of properties that should be initialized:
- ServiceOperationInfo: Indicates the service operation implemented by ReceiveActivity. This is set through the Choose Operation dialog box.
- CanCreateInstance: Indicates if the operation can be called to initialize the workflow instance. If not, the workflow must already be initialized before ReceiveActivity can accept calls.
- (ReturnValue): Associates the ReceiveActivity return value with a field or property of the workflow. Developers can set this field or property of the workflow to provide a return from the service operation.
- FaultMessage: Associates the ReceiveActivity fault message with a field or property of the workflow. Developers can set this value to return a fault from the service operation. The client receives this as a FaultException.
- [parameters]: These are dynamically generated properties based on the parameters to the service operation used to associate the parameter with a field or property of the workflow so that developers have access to these parameters throughout the ReceiveActivity sequence to implement service operation logic.
Figure 5 illustrates the property values of the first ReceiveActivity instance.
Figure 5: ReceiveActivity properties for ReceiveOperation1.
The Choose Operation dialog box shown in Figure 6 is used to set the ServiceOperationInfo property. From this dialog box you can either import an existing service contract (Import) and select one of its operations, or define a contract for the Workflow Service (Add Contract) and an operation (Add Operation) for the specific ReceiveActivity instance being configured. A subsequent ReceiveActivity instance can select the same contract and define additional operations. Workflow-first services imply that the WCF service contract does not exist until the Workflow Service is created. While designing the workflow, one or more service contracts can be defined with operations associated with ReceiveActivity instances. Typically, you ll create a single service contract (as shown in Figure 5) for the Workflow Service, with as many operations as ReceiveActivity instances. Figure 6 illustrates a service contract named IWFService with three service operations defined for the Workflow Service using the workflow-first approach.
Figure 6: The Choose Operation dialog box with a workflow-first service contract.
Note: One drawback to creating workflow-first services is lack of control over service contract properties, such as the target namespace. I recommend importing a service contract created specifically for the Workflow Service to overcome this limitation.
Workflow Service Configuration
Once the Workflow Service design is complete, and service contracts and operations are defined and associated with ReceiveActivity instances, it s time to think about Workflow Service configuration. Because a Workflow Service is implemented as a WCF service, each service contract must have at least one service endpoint defined so clients can communicate with the service. This is done with classic WCF configuration settings with the exception that it requires the use of a special context-aware binding. The following example illustrates a Workflow Service endpoint for the contract defined in Figure 6 using WSHttpContextBinding:
There are three context-aware bindings introduced with .NET Framework 3.5: BasicHttpContextBinding, WSHttpContextBinding, and NetTcpContextBinding. Each binding includes a context binding element to enable communication between clients and a specific workflow instance.
Workflow Service Context
Context-aware bindings facilitate passing the workflow
instance identifier in message headers between client and service. When the first
ReceiveActivity is called, the following
Because the client channel is configured to use the same context-aware binding, the client channel is responsible for caching this instanceId element for subsequent calls to the Workflow Service. The same header is sent for all calls from the same proxy instance to correlate the workflow instance at the server.
Should the client channel be faulted, a new proxy can be generated and initialized with the same instanceId. First, save the instanceId by retrieving its value through the context manager:
IContextManager ctxManager =
m_instanceId = ctx[ instanceId ];
If a new proxy is created and it is expected that the same workflow instance be used, create a new context with this value and assign it to the client channel:
m_proxy = new WinClient.localhost.WFServiceClient();
IContextManager ctxManager =
Note: If the Workflow Service is configured to use Workflow Persistence Services, the workflow instance state can be reloaded from the database. This makes it possible to survive service channel faults and machine restarts.
The sequence contained within a ReceiveActivity is executed synchronously as part of the WCF service operation. Parameters passed to the operation can be used by the activities in the sequence, and before the sequence ends the activity s return value or FaultMessage should be set. Activities that follow a ReceiveActivity in the workflow are executed asynchronously to the client (because a response will have already been sent back as the ReceiveActivity terminates).
For the Workflow Service defined in Figure 4, the CodeActivity executes before sending a response to the client. The following code inside the CodeActivity sets the return value:
this.ReceiveOperation1Return = "ReceiveOperation1 called";
this.ReceiveOperation1Fault = null;
If an exception occurs and the workflow should be terminated, a fault can be thrown by initializing the FaultMessage property through its bound field:
this.ReceiveOperation1Fault = new FaultException("ReceiveOperation1 has faulted.");
Activities that follow a ReceiveActivity continue to execute on the same thread as the ReceiveActivity although a response has already been sent to the client.
Note: Because activities placed within a ReceiveActivity are executed synchronously to the client, care should be taken that this sequence is not long running in order to avoid timeouts. Only those activities that contribute directly to the operation response need be part of the ReceiveActivity the rest can be executed asynchronously with the remainder of the workflow.
So far I ve focused on Workflow Services as exposing WCF service endpoints to clients so they can invoke operations implemented by ReceiveActivity instances. Another important feature of a Workflow Service is the ability to easily call out to WCF service operations without the hassle of prior techniques.
Using SendActivity, a Workflow Service can be configured to call a particular WCF service contract by simply providing the service contract metadata, indicating the operation to call, binding parameters to workflow fields or properties, and providing a configuration for the client proxy. The proxy is automatically generated based on the information provided to the SendActivity, so it is not necessary to write code to call the service unless you are customizing the call to provide a dynamic address or specific security settings.
Figure 7 illustrates the same Workflow Service from Figure 4 (modified to add a call to a WCF service operation within each ReceiveActivity). Think of this as the Workflow Service coordinating downstream service calls according to a business process.
Figure 7: A Workflow Service calling out to downstream WCF service operations.
As with ReceiveActivity, developers can configure each SendActivity by setting its properties. The key properties to initialize are:
- ServiceOperationInfo: Indicates the service operation to be invoked when the SendActivity instance is executed. This is set through the Choose Operation dialog box.
- EndpointName: A child of the ChannelToken property that specifies the WCF client configuration section to use for proxy initialization. This can be shared by several SendActivity instances by using the same ChannelToken.
- (ReturnValue): Associates the SendActivity return value with a field or property of the workflow. Developers can set this field or property of the workflow to share the return from the service operation with the rest of the workflow.
- [parameters]: These are dynamically generated properties based on the parameters to the service operation used to associate the parameter with a field or property of the workflow. This removes the need for code to initialize parameters passed to the service operation.
Figure 8 illustrates the property values of the first SendActivity instance.
Figure 8: SendActivity properties for Operation1.
To configure each SendActivity requires access to the service contract and any custom data types relied upon by that contract. The easiest way to gain access to this is to either generate a proxy, or, if you own both projects, you can share a metadata assembly between the Workflow Service project and the service project(s). Once this metadata is available to the project you can select the service contract and operation to associate with a SendActivity instance. After importing the service contract (see Figure 9) the same Choose Operation dialog box from Figure 6 is presented to select the operation for the SendActivity being configured.
Figure 9: Selecting a service contract to be used for SendActivity instances.
SendActivity instances also require access to a
WorkflowServiceHost is an extension to ServiceHost (the type responsible for initializing WCF communication channels at the service). WorkflowServiceHost adds functionality to facilitate communication between WCF and Workflow. When a request is received at a ReceiveActivity, the WorkflowServiceHost ensures the Workflow Runtime is initialized, initializes a new workflow instance if necessary (and if supported by the ReceiveActivity), then handles activating the workflow. For SendActivity instances, the WorkflowServiceHost constructs a client channel (or proxy) to call the specified service operation.
To host a Workflow Service, construct the WorkflowServiceHost as follows:
WorkflowServiceHost hostWFService = new
If the workflow-first approach was used to generate the WCF contract, the WorkflowServiceHost is smart enough to reflect the workflow definition for this contract (because it is not statically defined).
To host Workflow Services in IIS or WAS, use the WorkflowServiceHostFactory in the .svc declaration (full name required):
<%@ ServiceHost Service="SequentialWFService.
Next Up: Workflow Services and Security
In this article I introduced the Workflow Service, explained how to set up ReceiveActivity and SendActivity, and explained how the hosting model ties it all together. I have purposely left out security features for Workflow Services as that topic requires an article of its own. So, stay tuned to the next issue for the continuation of this discussion of Workflow Services as I explain your options for securing ReceiveActivity and SendActivity.
Download the samples for this article from http://www.dasblonde.net/downloads/aspprooct08.zip.
Michele Leroux Bustamante is Chief Architect of IDesign Inc., Microsoft Regional Director for San Diego, and Microsoft MVP for Connected Systems. At IDesign Michele provides training, mentoring, and high-end architecture consulting services focusing on Web services, scalable and secure architecture design for .NET, federated security scenarios, Web services, interoperability, and globalization architecture. She is a member of the International .NET Speakers Association (INETA), a frequent conference presenter, conference chair for SD West, and is frequently published in several major technology journals. Michele also is on the board of directors for IASA (International Association of Software Architects), and a Program Advisor to UCSD Extension. Her latest book is Learning WCF (O Reilly, 2007); visit her book blog at http://www.thatindigogirl.com. Reach her at mailto:[email protected], or visit http://www.idesign.net and her main blog at http://www.dasblonde.net.