Skip navigation

Introducing .NET 4.0 Workflow Services

Implement WCF services using WF workflows

In this column we dive deeper into one of the major new features in the forthcoming Windows Communication Foundation (WCF) 4.0 (which will be released with Visual Studio 2010), Workflow Services. Effectively, Workflow Services let you define services where service operations, and by extension service contracts, are defined using workflow activities. For more information on Workflow Services, see "Workflow Services" and "Designing Reliable Workflow Services."

Why Workflow Services?

With Workflow Services, service definitions can provide a level of implementation translucency not available with code, as they are graphically defined and configured. Using workflows to implement services not only makes the implementation accessible to the non-developer but also enables solutions to easily create a domain-specific vocabulary.

Workflow Services are built from workflows, and workflows are assembled from components referred to as activities; the model fundamentally encourages composition and reuse. This holds true for components that implement local service operations as well as for service orchestrations that coordinate calls across numerous remote services.

From an operations and debugging standpoint, Workflow Services delivers a win with a new unified tracing and tracking model that brings together WCF Tracing and Windows Workflow Foundation (WF) Tracking. This makes for a compelling service activity-monitoring experience that logs service calls, messages, and workflow activity details directly to the Event Log via Event Tracing for Windows (ETW) or your own custom repository.

Workflow Services bring other benefits. Their built-in support for long-running processes yields a simplified asynchronous programming model. The enhanced performance of the workflow runtime makes workflow-implemented services feasible even for services under demanding load. Finally, their declarative definition simplifies updates, versioning, and deployment and even enables .config-free service endpoints.

Workflow Basics

Before delving too far into Workflow Services, it helps to have a basic understanding of workflows. All workflows are implemented by composing activities, and the root layout that defines a workflow is itself an activity. In Workflow Services beta 1, two workflow activities are available: Sequence and Flowchart. Sequence, as it its name implies, is a great choice for expressing linear flows of execution.

With a Sequence, the layout of activities is rigid, flowing from top to bottom. If a loop is required, the Sequence must contain an activity, such as a While or ForEach, that supports looping over child activities. In other words, activities in a Sequence cannot loop back to a previous activity.

Flowchart provides an alternative to Sequence that supports arbitrary loops (that is, looping back to any previous activity). The goal of the Flowchart is to provide a more natural diagramming approach to workflow definition, and as such, activities in a Flowchart are free-floating and can be arranged as desired. The flow of execution is defined by the directed graph created by connecting activities with directional lines.

We'll explore the activities used to implement a service using either Sequence or Flowchart shortly. For now, let's turn to the runtime aspect and understand how workflows are hosted and executed by the workflow runtime.

Workflow Services Architecture

In .NET 3.5 you had Workflow Services, but hosting them was like hosting ASP.NET pages without Microsoft IIS: You had to do a lot of work to implement your own hosting platform. This difficulty disappears in .NET 4.0 with the native ability to host, support, and maintain .xamlx files (the file format used by Workflow Services) in IIS and the forthcoming Dublin distributed application server.

Workflow Services are defined in XAML files that have a .xamlx extension. These .xamlx files completely describe the workflow, its activities, and optionally any endpoints that won't be defined in a .config. If you're hosting within IIS, the experience of hosting a .xamlx is nearly identical to hosting an .svc: Your virtual directory needs to contain the .xamlx, and the bin directory contains assemblies defining any types (such as custom activities) used by your workflow and your web.config. In the web.config, you configure service behaviors that load extensions for persistence (which control how your workflow is serialized to persistent storage and removed from memory) and tracking (for defining where your service writes its logs as well as what it writes) and enable metadata exchange (for exposing the Web Services Description Language WSDL representing your service).

Just as for WCF Services using the ServiceHost, Workflow Services can be self-hosted in a standalone process outside of IIS by using the WorkflowServiceHost class. In either case, a Workflow Control Endpoint can be enabled to provide control (e.g., creating, running, terminating) over running workflow instances. Dublin provides a graphical interface to this endpoint when hosted within IIS with the Dublin extensions installed, but you're free to implement your own UI.

Building a Workflow Service

The process of building a workflow service is different from the process for implementing a traditional WCF service. Primarily this stems from the fact that you're replacing lines of code in a service operation's implementation with a composition of activities. From a high level, the differences are as follows: Service contracts are implicitly defined, service operation implementation is achieved with workflow activities, and service definitions are completely declarative XAML files.

The steps for building a workflow service are

1.     Create a new Declarative Flowchart/Sequence Workflow Service project.

2.     Define a service operation:

a.     Add a Receive activity and configure its input value.

b.    Add any activities that represent your operation's logic.

c.     Create a SendReply activity by copying from the Receive activity, and configure its return value as appropriate.

3.     Repeat step 2 for each service operation in your service.

4.     Adjust service configuration in .config, as needed.

5.     Deploy and host the workflow service.

To illustrate this, we'll build a simple calculator service containing one operation that simply takes as input two doubles and returns a double. We begin by creating a Declarative Sequential Service Library project.

Our new workflow already contains a Receive activity, so we just need to specify Add as the Operation Name. To specify the input parameters for Add, we need to fill in the Value argument. From the item template's defaults, Value has a value of data that is of type Int32. To specify a signature that contains multiple parameters (such as our two doubles), we need to define a payload by adding a new class file to our project and declaring the DataContract as follows:

[DataContract]

public class Arguments

{

[DataMember]

public double operand1 { get; set; }

[DataMember]

public double operand2 { get; set; }

}

Now we need to configure the data parameter's type as Argument. To change the parameter's type, we need to first select the Sequence, then click the Variables button at the bottom left of the workflow designer, as Figure 1 shows. From there, we can click the Variable type column, select Browse for Types from the drop-down menu to display the type selection dialog box, and choose Argument. (If the type isn't available under , you may need to build your project.)

Figure 1: Defining variables scoped to the selected activity using the Variables window

To enable the calculator to perform addition, we don't need additional activities. Instead we'll take advantage of the expression evaluation capability of activity arguments. For the Value argument of the SendResponse activity, we can write the following expression:

data.operand1 + data.operand2

From this, the SendReply activity will infer that the return type for our Add operation is of type double (and will expose it as such in the service contract). Figure 2 shows the finished workflow.

Figure 2: Completed AdderService workflow service

Our service implementation is now complete. We can test it easily by pressing F5, which launches the ASP.NET Development Server (WebDev.exe) and open Internet Explorer (IE) to the website hosting our .xamlx. If you navigate to the .xamlx file within IE, you'll receive the familiar service helper page that describes the URL to use to access the service's WSDL. With this information at hand, you follow the steps you'd have followed to build a client of a traditional WCF service. For a quick test, you can point WcfTestClient.exe at this URL and have it execute the addition with the parameters you supply.

Messaging Activities

Now that you've had a quick overview of how to build a workflow service, let's turn our attention to the activities used. Out of the box, there are six activities that play a role in defining a workflow service. The two "primitives" are Receive (for exposing a service operation) and Send (for making calls to other service operations), shown in Figure 3 and Figure 4, respectively.

Figure 3: Receive activity

Figure 4: Send activity

There are two activities for dealing with service replies: SendReply and ReceiveReply. SendReply, as shown earlier, is used to send the response (such as the return value) to the caller of a service operation. It's always tied to a particular Receive activity. In the case of making an outgoing call using a Send activity, the workflow will get the result of the invocation by using a ReceiveReply activity tied to the Send. Note that neither activity appears on the toolbox. You create them by right-clicking the Receive or Send activity and choosing Copy SendReply or Copy ReceiveReply, respectively.

Because the Receive/SendReply and Send/ReceiveReply is such a common pattern, .NET 4.0 includes two activities that define a Sequence containing each pair. These are the ReceiveAndSendReply and SendAndReceiveReply activities.

Defining Service Contracts

Workflow Services service contracts are defined implicitly by the collection of Receive activities in a workflow and their respective properties. Defining an operation contract for an individual service operation typically requires configuring three properties (highlighted in Figure 5).

Figure 5: Key Receive activity properties used in defining a service contract

We've already reviewed OperationName. The ServiceContractName is a string that identifies the service contract implemented by your workflow. All service operations having the same value for ServiceContractName will be exposed under a contract with that name this is what's meant by implicit contract definition. ValueType represents the data type of the Value property and effectively defines the signature of the parameters of the operation. Generally, configuring the Value property automatically sets ValueType to the appropriate data type.

The final property of interest on the Receive activity is CanCreateInstance. When this property is true (checked), a new workflow instance will be created in response to the service operation invocation.

Beyond configuring the Receive activity, the workflow's structure also affects the generated service contract. If a Receive isn't paired with a SendReply, then it's defining a one-way service operation. If it is paired with a SendReply, the result is a Request/Reply operation.

Defining Service Client Activities

When your Workflow Service needs to call other services, you can use a Send/ReceiveReply activity pair and configure the properties manually. However there's a much easier way. Within any of the Workflow Service projects, right-click the project name, choose Add Service Reference, and point the dialog to your target service, as Figure 6 shows.

Figure 6: Using Add Service Reference

Doing so will result in the generation of a custom activity that defines the sequence prewired to call the service and expose the input parameters and result as argument properties on the activity. Figure 7 shows the custom activity generated when creating a service reference to the Adder service. In addition, the client endpoint configuration needed for the service call will be added to an app.config in the same project. Simply build your project, and the custom activity will be available for immediate use in your workflow definitions.

Figure 7: The generated activity representing the Add operation

Service Configuration

Just as for traditional WCF services, you can separate the configuration of a workflow service from the service implementation by defining it either in an app.config (if self-hosting) or a web.config (if hosting in IIS). That said, the .xamlx also supports putting all configuration XML within it and creating a config-less service.

The connection between the .xamlx workflow service implementation and the corresponding service configuration in the *.config is specified in the .xamlx's WorkflowServiceImplementation element's ConfigurationName attribute (shown in Figure 8), which maps to *.config's service element's name attribute (Figure 9). With this link in place, a workflow service is configured in exactly the same fashion (using the same ServiceModel configuration section) as a traditional WCF service.

Figure 8: Excerpt of the AddService's .xamlx

Figure 9: Excerpt from the AdderService's web.config

Pairing Messages to Workflow Instances with Correlation

The problem of routing an incoming message to a particular workflow instance is a solved by correlation. In WF 3.5, a message was routed to the correct workflow instance by the runtime because it contained a special header that contained a GUID naming the target workflow instance (known as Context Based Correlation). WF 4 introduces a new and more flexible approach to correlating messages to workflow instances that can use any part of the message by means of one or more XPATH queries, collectively referred to as a Correlation Query.

In general, one doesn't need to bother with writing the XPATH queries that define the correlation query; the workflow designer will build it provided the type of the message is known at design time. Recall that the message type is effectively driven by the ValueType property present on both the Send and Receive activities. For example, if you want to correlate based on both input operands on the Receive defining the Add operation in the AdderService, you click the ellipses next to the Correlates With property in the property grid.

Figure 10 shows the final configuration needed to correlate on the values of both operands using the Correlations dialog. You need to specify a correlation handle variable (an opaque variable used by the workflow to refer to correlations), a name for the correlation query, and the XPATH queries that define the correlation query. The project template automatically provides you with one variable "handle" scoped to the sequence to use it, just type its name into the Correlates With box. The Correlation Query Name is a simple string name. The Queries grid provides one row per XPATH and allows you to provide a user-friendly name for each XPATH.

Figure 10: Correlations dialog box

To get the XPATH for an operand, click the ellipses in the XPath column. Doing so will display the CorrelationQuery Value dialog (Figure 11). Expanding the Arguments node allows you to see the two members. Selecting one and clicking OK will insert the appropriate XPATH into the XPath column.

Figure 11: CorrelationQuery Value dialog

Correlation Applied: Asynchronous Operations

Correlation makes it easy to build workflows that can make asynchronous calls; that is, they make an outgoing service call, then perform other work or persist waiting for the called service to return with the result of the operation. By initializing the correlation on the Send and waiting for the correlated value later on with the Receive (accomplished in both cases by configuring the correlation as above), an external service can call back into the right workflow instance. Meanwhile, the calling workflow is able to perform additional work.

Debugging and Monitoring

When building your workflow services, if you run them via F5 they'll be hosted in the ASP.NET Development Server with the .NET 4 Workflow Debugger attached. This enables you to graphically step through a workflow service's execution, set break points, and examine workflow variable values in the local windows. If you're attempting to debug a workflow service hosted in IIS, you can take the standard approach: Choose Attach to Process from the Debug menu and attach to the worker process (such as w3wp.exe).

What if you're trying to troubleshoot a workflow service to which you can't directly attach the debugger (e.g., on a production box)? This is where the new integrated ETW tracing and tracking comes into play. ETW events are viewable from the Event Viewer, under Application and Service Logs\Microsoft\WCF\WF-Development. While you're troubleshooting, you can enable the Debug and Analytic logs, which collectively will provide you detailed information ranging from the service operations invoked on the local machine, the messages logged, any exceptions thrown, and TrackingRecords emitted by workflow execution. The latter can include logging event details for workflow state changes, activity state changes, and user records emitted by custom activities.

Enabling ETW tracking for your workflow service is a matter of configuring a service behavior that references an ETW Tracking Participant in the web.config. In addition, you can configure a Tracking Profile that defines filters for which workflow Tracking Records to log and, if desired, which workflow variable values to extract given the occurrence of a particular tracking event. Figure 12 shows the serviceModel section for the AdderService, which enables ETW tracking with a profile that logs when the workflow starts and ends, along with any exceptions encountered.



  

    

    

  

  

    

      

        

        

        

          

        

      

    

  

  

    

      

    

    

      

        

          

            

              

              

            

          

          

          

          

            

          

        

      

    

  

Figure 12: Enabling ETW tracking

Go with the Flow

I've showed you how Workflow Services provides a robust environment in which to define your services declaratively using workflow activities. To the outside world, they appear for all intents and purposes like code-based services but have the readability of flow diagrams. These services can then be hosted in IIS and monitored using the Event Viewer. Now that you have an understanding of the fundamentals, you can start using Workflow Services and get a feel for how they'll benefit your applications.

Zoiner Tejada ([email protected]) is passionate about workflow and the future of implementing connected systems with them. He's the chief software architect at Hershey Technologies, is recognized as a Microsoft Industry Influencer, and is an advisor to Microsoft's Connected Systems Division. Zoiner has a degree in computer science from Stanford University and blogs at TheWorkflowElement.com.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish