Hour 19 Learning WF-WCF Integration

What You Will Learn in This Hour:

Image    Overview of Windows Communication Foundation

Image    Exposing WF workflows as WCF services

Image    Accessing WCF services from WF workflows

Image    Directly Accessing the WF runtime from the WCF host

Overview of Windows Communication Foundation

Before jumping directly into how to use Windows Communication Foundation (WCF) with WF, this section provides an overview of WCF and the next provides an overview of using the two together.

WCF and WF are complementary products that are both part of the .NET 3.0 and 3.5 Frameworks. WCF is Microsoft’s distributed computing technology. It is the preferred way to provide and access network endpoints on the Microsoft platform. WCF subsumes all previous Microsoft distributed technologies, including web services, web service enhancements, .NET remoting, and enterprise services. WCF supplies the most thorough web service standard support on the Microsoft platform. WCF can listen for and access network endpoints via HTTP, TCP, named pipes, and just about any other communication protocol.

In the past, enterprise services and .NET remoting were frequently the best choices when communicating behind the firewall, whereas web services were generally best when communicating across the firewall. This required using different programming and security models based on the communication pattern. If the service had both cross-firewall and local clients, this frequently required creating web service and .NET enterprise service or .NET remoting endpoints as well. Even when using web services, you could choose between standard and employing web service enhancement technology (WSE) to gain additional security.

WCF rationalizes distributed computing on the Microsoft platform by providing one programming model and one runtime. It separates the service (the functionality) from the endpoint. The endpoint contains the information necessary to communicate on the wire. A service communicating across the firewall can choose the WCF HTTP binding, which sends standard SOAP over HTTP using basic security. A service also requiring additional security can use the sibling HTTP binding that includes WS* security. Finally a service communicating behind the firewall can utilize the TCP binding that uses compiled SOAP. Therefore, the same service can support all three communication patterns. There needs to be one WCF endpoint created for each communication pattern the service supports. WCF can also use MSMQ when queuing is necessary; it is just another binding. Finally, to streamline endpoint support even more, WCF binding information can be placed in configuration files, allowing the wire format to change without requiring recompilation.

WCF can be hosted in any .NET 2.0 or later application domain, such as a Windows Service, IIS, or Windows Activation Service (improved IIS in Windows 2008) process. The ability to listen across just about any protocol securely and reliably, in any Windows process, and to do so at maximum efficiency makes WCF very powerful. WCF abstracts service functionality from wire format and hosting requirements. There really is no reason not to use WCF for distributed computing on the Microsoft platform. Because of WCF’s adept endpoint capabilities, it is commonly referred to as Microsoft’s service-oriented technology, with the endpoints being the entry points to the services. As you will see, WF or standard .NET types can provide the logic behind the endpoint.

WF and WCF Overview

Workflows frequently need to be exposed across the network and to access other services on the network. WF can leverage WCF as the endpoint while it provides the logic component of the network service. A customer service, for example, may be exposed as a WCF endpoint and also call out to a credit service. In this case, the WF workflow can be exposed as a WCF endpoint and can utilize WCF to call the credit service as well. WCF is WF’s conduit to and from the outside world when working with distributed systems.

WCF provides two activities and hosting capabilities to WF in .NET 3.5 (Figure 19.1. The Send activity provides functionality similar to both the CallExternalMethod activity and the InvokeWorkflow activity. The Receive activity is similar to the HandleExternalEvent activity (and the response portion of the InvokeWorkflow activity). Each activity can be associated with an interface and configured to support synchronous or asynchronous operations. The Send activity, for example can call a method on a service or workflow (that is exposed as a service), pass in parameters, and receive a response, just as a standard method can. The Receive activity provides the same capabilities in the other direction, it receives responses rather than requesting them.

FIGURE 19.1 WCF .NET 3.5 activities.

WCF .NET 3.5 activities.

Having all the flexibility of method calls baked into WF activities that can be used to call services and workflows is quite powerful. It is certainly an improvement over .NET 3.0, where calling to and from the host is not optimum. Workflow to host must be synchronous and host to workflow must use asynchronous events and a special EventArgs-derived payload. Calling workflows is even harder in .NET 3.0, especially to do so synchronously. By and large, the communicating to and from workflows is greatly improved in .NET 3.5. The communication is, however, a work in progress. Correlation (Hour 8, “Working with Parallel Activities and Correlation”) is not particularly straightforward to implement at the current time with WorkflowServices.

The third main component of WF-WCF integration is WCF hosting. The WCF Receive activity works in conjunction with the WorkflowServiceHost type to host WF workflows and to create endpoints. These endpoints are called WorkflowServices. When placing a Receive activity on a WF workflow, WCF (or the WorkflowServiceHost type) must host the workflow. Built-in capabilities simplify hosting WCF (and WorkflowServices) in IIS and WAS (IIS in Vista and Windows Server 2008). WCF can also be hosted in Windows Services, Console applications, Windows Forms applications, and other .NET processes, although it is still up to you to manage the lifetime in these applications.

Because of the capability of the Send and Receive activities, the IIS and WAS hosting advantages, and the apparent emphasis toward WCF as a hosting technology going forward, it is reasonable to consider hosting all WF applications as WorkflowServices. Another reason not to host WF in WCF is when using another dedicated WF host product, such as SharePoint or MS CRM. In these cases WCF can still be used to access endpoints, but they are the workflow hosts.

Image

In .NET 3.0, WF and WCF must be integrated manually. No WorkflowServiceHost type or Send and Receive activities exist. Manual integration is not covered in this book.

There are two workflow-specific projects in the 3.5 Framework. The first contains a sequential workflow project and a WCF contract (interface). The second holds state machine workflows and an accompanying contract. These project types are relevant when exposing a workflow as a service.

The first two exercises in this hour are part of hosting a WF workflow in WCF. They are broken into smaller steps to help digest them.

You begin this hour hosting a workflow in WCF (creating a WorkflowService). You perform this in two steps. First, you use the interface and Receive activity prepopulated with the Sequential Workflow Service Library template. This allows you to create functional WorkflowService with minimal work. Then you modify the interface and reconfigure the existing Receive activity to use the new interface. The combination of the two parts demonstrates all the standard steps to create a functional WorkflowService.

Next, you learn to access the WF runtime form the WorkflowServiceHost. By default, the WF runtime is loaded as part of the WorkflowServiceHost under the hood. You will need to access it many times—for example, to register events and add runtime services. Finally, you will call another workflow from a workflow using the Send activity.

Image

WCF is an extremely large subject. Its coverage is limited to that necessary for it to host and be called from WF. If you want more detail on WCF, see Essential Windows Communication Foundation (WCF): For .NET Framework 3.5 (Addison-Wesley, Steve Resnick, Richard Crane, and Chris Bowen), MSDN, or other sources.

Hosting a Workflow in WCF Using Existing Interface and Receive Activity

In this exercise you create a WCF endpoint that hosts a WF workflow. You create a client application to access the WCF host (that runs the workflow). You will leverage the interface and Receive activity created by the WCF Sequential Workflow Service Library project to reduce the steps necessary to see a WF workflow run in WCF.

Creating the Solution and Projects

This solution contains three projects. The first holds the WF workflow and contract. The second holds the WCF host, and the third holds the client.

Creating the Solution

Follow the next steps to create the solution.

1.   Start Visual Studio 2008. Select File, New, Project.

2.   Expand the Project Types and select Other Project Types.

3.   Select the Visual Studio Solutions project template.

4.   Enter WcfHostsWfSolution as the Name.

5.   Enter or browse to C:SamsWf24hrsHoursHour19LearningWF-WCFIntegration for the Location.

6.   Click OK.

Creating the Sequential Workflow Service Library Project

Follow the next steps to create a Sequential Workflow Service Library project that will hold a workflow ready to be hosted in WCF.

1.   Right-click WcfHostsWfSolution in the Solution Explorer and select Add, New Project.

2.   Expand Visual C# and select WCF (Figure 19.2).

FIGURE 19.2 WCF project types.

WCF project types.

3.   Select the Sequential Workflow Service Library project template.

4.   Enter ContractsAndWorkflows as the Name.

5.   Leave the default path.

6.   Select OK.

Creating the Remaining Projects

Follow the next steps to create the console host and console client project.

1.   Create a Console Application project and name it ConsoleApplicationWcfWorkflowHost. This project will serve as the WCF Host project.

2.   Create a Console Application project and name it ConsoleApplicationClient. This is the client that will call the WCF endpoint that hosts the WF workflow.

ABCs of WCF and WF Specific Bindings

WCF endpoints contain an address, a binding, and a contract. The address is the location of the service. The Sequential Workflow Service Library project template created the following address for the Workflow1 service to facilitate testing: http://localhost:8731/Design_Time_Addresses/ContractsAndWorkflows/Workflow1/. Open the App.config file in the ContractsAndWorkflows project and you will see this address in the baseAddresses element. A couple of lines below, the binding is set to wsHttpContextBinding and the contract to ContractsAndWorkflows.IWorkflow1. By leaving the address null, it is created by adding the service name to the baseAddress.

Image

The bindings dictate the method the service listens for and how it interacts with clients. Change the binding and the service can communicate over a new protocol. You will see at the end of this topic that new bindings were created to permit WCF to host long-running workflows. These bindings permit WCF to retain context across WF workflow persistence points. This exemplifies the power of WCF bindings. They dictate much more than protocols.

These three elements are commonly referred to as the ABCs of WCF. For a WCF client to connect to a WCF host, they must both have identical ABCs. That is, the client connects to the service at the address, over the binding, and via the contract the service specifies. WCF ships with support for a number of bindings. These include the BasicHttpBinding, WsHttpBinding, and NetTcpBinding bindings. The difference between the BasicHttpBinding and the WsHttpBinding is that the latter includes web services security and reliable message support under the WS* umbrella of standards.

Custom WCF bindings can be created when none of the out-of-the-box WCF bindings work for your scenario. When WCF hosts WF, it needs to maintain session across the workflow persists and activations. Three custom bindings permit WF session state to be managed from WCF: BasicHttpContextBinding, WsHttpContextBinding, and NetTcpContextBinding. As you can see by the name, one is for standard http, another is for WS*-compliant http, and the last is for TCP.

Exploring the ContractsAndWorkflows Project and Bindings

The ContractsAndWorkflows project contains a WCF interface, a workflow that implements it, and a configuration file that specifies the endpoint information.

Reviewing the Interface

The interface (IWorkflow1.cs) has a ServiceContract attribute, and its GetData operation is decorated with an OperationContract attribute (see the next code snippet). The ServiceContract attribute informs WCF that this interface can be used to create WCF services. The OperationContract attribute states that this operation should be available to service consumers. Operations can exist in a WCF interface that are not available as WCF service operations. Only the operations with OperationContract attribute are available. Also, note the standard interface convention. No mandate requires that a synchronous method be used for workflow-host communication and that an asynchronous event be used for host-workflow communication. Any combination of synchronous and asynchronous operations can be used. In this case, a standard synchronous operation delivers the complete roundtrip communication between workflow and host.

namespace ContractsAndWorkflows
{
    // NOTE: If you change the interface name "IWorkflow1" here, you must also
update the reference to "IWorkflow1" in App.config.
    [ServiceContract]
    public interface IWorkflow1
    {

        [OperationContract]

        string GetData(int value);

        // TODO: Add your service operations here
    }
}


Exploring the Receive Activity

The workflow created by the Sequential Workflow Service Library Project template is prepopulated with a Receive activity. The Receive activity is used when workflows are hosted in WCF. The Receive activity works in conjunction with the WorkflowServiceHost type. The WorkflowServiceHost type is used when WCF endpoints host WCF workflows. The operations exposed by the Receive activity and data it exchanges with clients are specified in an interface.

Follow the next steps to explore the Receive activity and its properties.

1.   Open the workflow in design mode.

2.   Click the Receive activity and look at its properties (Figure 19.3).

FIGURE 19.3 Receive activity and its properties.

Receive activity and its properties.

Let’s examine each of the Receive activity’s nongeneric properties starting with ServiceOperationInfo and then going from the top down:

Image   ServiceOperationInfoBinds the Receive activity to a service contract (interface) operation. As you can see, it is bound to the GetData operation from the IWorkflow interface that was created with the project.

Image   ReturnValueThe value returned to the client when the Receive activity completes execution. The Receive activity is a composite activity, as will be demonstrated in the next section.

Image   ContextToken—This is used for correlation purposes when the client contacts multiple Receive activities on the same workflow. This token ensures that subsequent calls access the proper instance of the workflow. The concept is identical to the CorrelationToken used on CallExternalMethod and HandleExternalEvent activities covered in Hour 8.

Image   FaultMessageAllows a fault message to be sent to the client if a problem arises. Returning fault messages is the standard way to return an error to a client when web services are used.

Image   OperationValidationValidation logic to be executed before message is accepted. One possibility is to perform role checking.

Image   ValueThe parameter specified in the interface.

The ContextToken, FaultMessage, and OperationValidation properties are not covered in this book. The others are used in this hour.

Click the workflow (not the Receive activity), look in the property window, and you will see the WorkflowServiceAttributes property. It is a new property that is promoted to the workflow when a Receive activity is added. It contains a number of WCF-centric properties, including one that specifies whether exception details are included in faults. These properties are not covered anymore, but you should make a mental note for when you might need them.

Modeling the Workflow

As mentioned, the Receive activity is a composite activity. All activities placed in it will be executed before it completes and returns a value to the client.

Follow the next steps to see the default properties and to place a Code activity into the Receive activity.

1.   Open the workflow in code view and you will see ReturnValue and InputValue properties that were bound to the Receive activity ReturnValue and value properties.

2.   Place a Code activity in the Receive activity. Double-click it and add the following code to its handler:

                                                                // Set the return value based on the customer number
                                                                ReturnValue = InputValue == 1 ? "Good" : "Bad";


The workflow is shown in Figure 19.4. The Code activity evaluates the value passed in and returns either good or bad based on the value received.

FIGURE 19.4 Workflow with Receive activity and Code activity placed in Receive activity.

Workflow with Receive activity and Code activity placed in Receive activity.

Looking at the App.config File

Open the App.config file. There is a lot of XML noise. The WCF content is held in the system.serviceModel element. The Services element contains the service name and a behaviorConfiguration attribute, which I will explain shortly. The baseAddress plus the address attribute of the endpoint element holds the service address. In this case the address attribute is blank, so the entire address is held in the baseAddress. The identity element holds the identity and comments you should read. Finally, the next endpoint element holds the address to the service metadata. This is where the WSDL can be accessed and will be used to create proxy and an App.config file later.

  <system.serviceModel>
    <services>
      <service name="ContractsAndWorkflows.Workflow1"
behaviorConfiguration="ContractsAndWorkflows.Workflow1Behavior">
        <host>
          <baseAddresses>
            <add
baseAddress="http://localhost:8731/Design_Time_Addresses/ContractsAndWorkflows/Wo
rkflow1/" />
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding="wsHttpContextBinding"
                  contract="ContractsAndWorkflows.IWorkflow1">
          <!-- Upon deployment, the following identity element should be removed
or replaced to reflect the identity under which the deployed service runs.  If
removed, WCF will infer an appropriate identity automatically.-->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>


The behavior element contains other information about the service, such as permitting HTTP Get to be used to access the metadata, which allows it to be viewed in a browser.

    <behaviors>
      <serviceBehaviors>
        <behavior name="ContractsAndWorkflows.Workflow1Behavior"  >
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceCredentials>
            <windowsAuthentication
                allowAnonymousLogons="false"
                includeWindowsGroups="true" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>


Services can be configured in code or via configuration file. The advantage of using a configuration file is that it can be changed without recompiling the service, and potentially done so by administrators. You will use the configuration file created by the WCF Sequential Workflow Service Library project template when creating the host in the next section

Creating the WCF Endpoint and Host

WCF, like WF, can be hosted in any .NET 2.0 or later app domain. The ServiceHost type, contained in the System.ServiceModel namespace, is the gateway to WCF, much like the WorkflowRuntime type is the gateway to WF functionality. When WCF hosts a workflow, the WorkflowServiceHost type, contained in the System.WorkflowServices namespace, is used in place of the ServiceHost type. The WorkflowServiceHost type contains a handle to the WF runtime, thereby permitting a WCF host to run a WF workflow, register runtime events, and add runtime services. The WCF endpoint will be hosted in a Console Application.

You will implement a WorkflowServiceHost, set up an endpoint, and allow metadata to be accessed. The endpoint information will be extracted from the App.Config file in the workflow project.

Performing Preliminary Setup

Follow the next steps to add references to the assemblies needed to host a WF workflow in WCF. Then reference the project holding the workflow to be run.

1.   Click the ConsoleApplicationWcfWorkflowHost project in the Solution Explorer.

2.   Add references to System.ServiceModel, System.Workflow.Activities, System.Workflow.ComponentModel, and System.WorkflowServices.

3.   Add a reference to the ContractsAndWorkflows project.

4.   Open Program.cs and add the following using directives:

                using System.ServiceModel;
                using System.ServiceModel.Description;


Instantiating WorkflowServiceHost

The WorkflowServiceHost needs to know where to listen (address) and what to listen for (contract or type). All this information will be obtained from the configuration file.

Follow the next steps to move the App.config file from the workflow project into the console host. Then add code to the Program.cs file to instantiate the WorkflowServiceHost.

1.   Cut the App.config file from the ContractsAndWorkflows project and copy it into the ConsoleApplicationWcfWorkflowHost project.

2.   Now it is time to instantiate the WorkflowServiceHost type and to pass it the type (the workflow). Add the following code to the top of the Main method in Program.cs in the ConsoleApplicationWcfWorkflowHost project:

                                                  // Instantiate the WorkflowServiceHost and pass it the
                                                 // workflow (type) to invoke.
                                                 WorkflowServiceHost selfWorkflowHost =
                                                            new
              WorkflowServiceHost(typeof(ContractsAndWorkflows.Workflow1));


Start, Pause, and Close the Host

Follow the next steps to open the host to start it listening and build the project. The workflow will run in its context. Then you will pause the host while it waits. This must be done, just as with WF, because this is a console application and the console application will complete if not blocked while running workflows (or waiting for workflows to run) that run asynchronously, which is the default.

1.   Add the following code to open the host, to pause it, and finally to close it:

                                            // Open the service so that it starts listening for client calls.
                                            selfWorkflowHost.Open( );

                                 // Pause the host while it waits for clients to invoke
                                 // workflow through it.
                                 Console.WriteLine("The service is ready.");
                                 Console.WriteLine("Press <ENTER> to terminate service.");
                                 Console.WriteLine( );
                                 Console.ReadLine( );

                                 // Close the service.
                                 selfWorkflowHost.Close( );


2.   Build the ConsoleApplicationWcfWorkflowHost project.

Running the Host

The host can now be started and the endpoint can begin listening. The WCF host must be running before it can be referenced by the client you will create in the next section, so leave it running when you’ve completed this section.

Follow the next steps to configure the order the projects should start in and then run the project.

Image

We will use the multiple startup project option because Visual Studio 2008 is required to use the functionality in this hour.

1.   Right-click the solution in the Solution Explorer, select Properties, and click the plus sign to expand Common Properties. Select Startup Project, and select the Multiple Startup projects option in the middle of the dialog. Select the ConsoleApplicationWcfWorkflowHost project in the list of projects, click the arrow to the right of it, and select Start from the drop-down. Then click OK.

2.   Press F5 to start the project (all projects specified to start). You should see the host has started and is waiting to receive a client request that it will, in turn, pass onto the workflow as shown in Figure 19.5.

FIGURE 19.5 WCF Host running.

WCF Host running.

3.   Terminate the ConsoleApplicationWcfWorkflowHost.

Creating the Console Application Client

There are two steps to creating the client. The first is referencing the WCF host to build a proxy and a configuration file. The second step is to add the logic to the client to instantiate and invoke the method on the workflow proxy.

Performing Preliminary Setup

Follow the next steps to add referencing and a using directive.

1.   Click the ConsoleApplicationClient project in the Solution Explorer.

2.   Add a reference to System.ServiceModel.

3.   Add a reference to the ContractsAndWorkflows project.

4.   Open Program.cs and add the following using directive:

                 using System.ServiceModel;


Adding a Service Reference to the WCF Host

The client needs to reference the service (much the same as a client to an ASMX web service needs to reference the web service). The client may be on the same computer or access the service across the Internet.

Follow the next steps to add a service reference from the client to the host using the Svcutil.exe command line utility.

Image

You can also add a client reference to a service by right-clicking the project and choosing Add Service Reference (similar to adding an ASMX web service reference) or by using the Svcutil.exe utility. The first is a little easier but does not offer much control. Therefore, we will use Svcutil.exe to add service references in this book.

1.   Press F5 to start running the ConsoleApplicationWcfWorkflowHost.

2.   Select Start, All Programs, Visual Studio 2008, Visual Studio Tools, and Visual Studio 2008 Command Prompt.

3.   Enter cdSamsWf24hrsHoursHour19LearningWF-WCFIntegrationWcfHostsWfSolutionConsoleApplicationClient to go to the client directory.

4.   Enter the following command to generate a proxy and a configuration file in the current directory. The HTTP address is taken from the baseAddress element of the App.config file in the ContractsAndWorkflows project and must match the address where the service runs. (Remember the host must be running before you reference it.)

                svcutil.exe /language:cs /out:GeneratedProxy.cs /config:app.config
                http://localhost:8731/Design_Time_Addresses/ContractsAndWorkflows/Workflow1/


5.   Two files, one named GeneratedProxy.cs and the other App.config should have been created.

6.   Stop the host project from running. You must do this to include the file in the project in a couple of steps.

7.   Go back to Visual Studio and click the ConsoleApplicationClient project in the Solution Explorer.

8.   Click the Show All files icon and the just generated files; a couple of directories should appear in a dimmed format (Figure 19.6). It is a toggle, so click again if you do not see the files.

FIGURE 19.6 Show All files icon with all files included.

Show All files icon with all files included.

9.   Select the GeneratedProxy.cs and the App.config files. Then right-click and choose Include in Project. They should no longer be dimmed.

Image

The default behavior of SvcUtil is to create a new ServiceModel element if there is an existing App.Config file and to create a new one otherwise. However, a command-line option exists (mergeConfig) that will merge the new endpoints into an existing ServiceModel element. You can explore numerous options by entering SvcUtil from the command prompt.

Exploring the Generated Files

The GeneratedProxy.cs, as the name implies, is a proxy. It is used to call the service. The App.config file contains the service endpoint configuration details. Follow the next steps to look at the generated files.

1.   Open the GeneratedProxy.cs file. Skip down to the public partial class Workflow1Client. This is the class you will instantiate in the client, and its GetData operation will access the method on the workflow Receive activity.

2.   Open the App.config file. The client’s App.config file contains bindings and client elements. The binding element specifies the binding to connect to the service—wsHttpContextBinding in this case. Other binding-related properties exist, such as the timeout value.

3.   The Client element at the bottom of the file contains the address, binding, and contract to use to contact the service. These values must match the service values for the client to connect.

Adding Client Code to Call the Service

Now that the client has a reference to the service, follow the next steps to instantiate the proxy and call the service, which will, in turn, call the workflow.

1.   Open Program.cs in the ConsoleApplicationClient project.

2.   Add the following code to instantiate an object to call the service, which then invokes the workflow. The address, binding, and contract are retrieved from the configuration file.

                                                                // Instantiate the WorkflowInterfaceClient from the proxy.
                                                                // Endpoint information is retrieved from the config file.
                                                                Workflow1Client client = new Workflow1Client( );


3.   Add the following code to call the workflow’s GetData method, again through the service.

                                                                // Call the GetData method on the workflow
                                                                string status = client.GetData(1);
                                                                Console.WriteLine("the status is: " + status);


4.   Pause the host:

                                                                Console.WriteLine("Press Enter to terminate the client.");
                                                                Console.Read( );


5.   The completed client Program.cs Main method should look like this:

                                                    static void Main(string[ ] args)
                                                   {
                                                                // Instantiate the WorkflowInterfaceClient from the proxy.
                                                                // Endpoint information is retrieved from the config file.
                                                                Workflow1Client client = new Workflow1Client( );

                                                                // Call the GetData method on the workflow
                                                                string status = client.GetData(1);

                                                Console.WriteLine("the status is: " + status);

                                                Console.WriteLine("Press Enter to terminate the client.");
                                                Console.Read( );
                                       }


6.   Build the ConsoleApplicationClient project.

Running the Client

The service should still be running. If not, start it so that the client can access it. Follow the next steps to configure the client project to start in the Multiple Startup projects choice and run the solution.

1.   Right-click the solution in the Solution Explorer, select Properties, and click the plus sign to expand Common Properties. Select Startup Project, select the Multiple Startup projects option in the middle of the dialog. Select the ConsoleApplicationClient project in the list of projects, click the arrow to the right of it, and select Start from the drop-down.

2.   Click the ConsoleApplicationWcfWorkflowHost project and click the up arrow to the right of the list until it is the first project in the list to ensure it starts first. Then click OK.

3.   Press F5 to start the projects. You should see that the client ran and retrieved the status from the workflow (Figure 19.7).

FIGURE 19.7 Console client receives response from the workflow.

Console client receives response from the workflow.

4.   Stop both the client and host projects.

Hosting a Workflow in WCF: Configuring Receive Activity and Updating Interface

In the previous exercise, you created a workflow, host, and client, and then connected them all. You leveraged the Receive activity, interface, and service created with the Sequential Workflow Service Library project template. In this exercise, you modify the interface, delete the existing Receive activity, add a new Receive activity, and configure the new Receive activity.

Modifying the Interface

WCF interfaces are decorated with ServiceContract and their members with OperationContract, as well as other attributes that delineate they are available to interact with clients. Follow the next steps to decorate the IWorkflow interface as appropriate.

1.   Open the IWorkflow.cs file in the ContractsAndWorkflows project.

2.   Replace the current GetData method with the following GetStatus method (leave the attribute):

        string GetStatus(string customer);


3.   Delete the remaining interface content. The IWorkflow1 interface should now look like this:

    [ServiceContract]
    public interface IWorkflow1
    {
        [OperationContract]
        string GetStatus(string customer);
    }


Image

The workflow implements the interface. When configuring the workflow in the next step you will implement the interface. In a nonworkflow implementation, there would be a class that implements the interface.

Configuring the Receive Activity

There should be a red exclamation error mark on the Receive activity, as the method it points to no longer exists. Follow the next steps to delete the existing Receive activity and configure a new one. This will allow you to start from the beginning.

1.   Open the workflow in code view and delete the code that initializes the properties and variables. The only code remaining in the class should be the constructor and the code activity handler as shown:

    public sealed partial class Workflow1 : SequentialWorkflowActivity
    {
        public Workflow1( )
        {

                  InitializeComponent( );
               }

                private void codeActivity1_ExecuteCode(object sender, EventArgs e)
                {

                    // Set the return value based on the customer number
                    ReturnValue = InputValue == 1 ? "Good" : "Bad";
                }
    }


2.   Move the Code activity from Receive activity to the workflow.

3.   Delete the existing Receive activity, and add a new Receive activity to the workflow.

4.   Move the Code activity into the Receive activity you just added.

5.   Click on the Receive activity. Then click on its ServiceOperationInfo property and click the ellipsis.

6.   The Choose Operation dialog is spawned (Figure 19.8).

FIGURE 19.8 Choose Operation dialog.

Choose Operation dialog.

7.   Select the Import icon in the upper-right corner.

8.   The Browse and Select a .NET Type dialog is displayed. Expand Current Project, select ContractsAndWorkflows, and choose IWorkflow1 in the middle pane. Click OK.

9.   You are returned to the Choose Operation dialog, where the GetStatus method shows (Figure 19.9). Only one method is in the interface, so you can click OK. If there were multiple methods, you would choose which one to apply to this Receive activity.

FIGURE 19.9 Populated Choose Operation dialog.

Populated Choose Operation dialog.

10.   Click the CanCreateInstance property and set it to True. This tells WF to start a new instance when a message for this Receive activity is received. If there were multiple Receive activities, the subsequent Receive activities would not invoke a new workflow instance. They would instead use an existing instance.

11.   Bind the ReturnValue property to a new field. Click the ReturnValue property. Click the ellipsis, select the Bind to a New Member tab, select the Create Field option button, name it ReturnValue, and choose OK.

12.   Bind the customer property to a new field. Click the customer property. Click the ellipsis, select the Bind to a New Member tab, select the Create Field option button, name it Customer, and click OK.

13.   Modify the Code activity handler to compare to a string rather than an int by replacing it with the following code:

                    // Set the return value based on the customer number
                    ReturnValue = Customer == "1" ? "Good" : "Bad";


14.   Stop the host if it is still running.

15.   Build the entire solution.

The Receive activity (therefore service implementation) and interface are now updated.

Rebuilding the Client

In this section, you will update the proxy and change the client to invoke the new method as well.

Rebuilding the Client Proxy

The client proxy is not pointed at the GetStatus method. It is still pointed at the GetData method contained in the original contract. Follow the next steps to run SvcUtil again to update the proxy to point to the correct operation. Then start the host project manually because you do not want all projects to execute.

1.   Delete the GeneratedProxy.cs and the App.config files from the ConsoleApplicationClient project by right-clicking them and selecting Delete.

2.   Start the host by going to the C:SamsWf24hrsHoursHour19LearningWF-WCFIntegrationWcfHostsWfSolutionConsoleApplicationWcfWorkflowHostinDebug directory in Windows Explorer and double-clicking the ConsoleApplicationWcfWorkflowHost.exe file.

3.   Select Start, All Programs, Visual Studio 2008, Visual Studio Tools, and Visual Studio 2008 Command Prompt.

4.   Enter cdSamsWf24hrsHoursHour19LearningWF-WCFIntegrationWcfHostsWfSolutionConsoleApplicationClient to go to the client directory.

5.   Enter the following command to generate a proxy and a configuration file in the current directory.

svcutil.exe /language:cs /out:GeneratedProxy.cs /config:app.config
http://localhost:8731/Design_Time_Addresses/ContractsAndWorkflows/Workflow1/


6.   Terminate the host project. You must do this to include the file in a couple of steps.

7.   Go back to Visual Studio and click the ConsoleApplicationClient project in the Solution Explorer.

8.   New versions of the GeneratedProxy.cs and the App.config should have been created. If the files are not shown, click the Show All Files icon once or twice until they appear.

9.   Select the GeneratedProxy.cs and the App.config files. Then right-click and choose Include in Project. They should no longer be dimmed.

10.   Go to the bottom of the GeneratedProxy.cs file and make sure it is invoking the GetStatus method and not the GetData method. If not, build the solution again, and then go back to step 1 to start over.

Updating the Client to Invoke the New Method

Follow the next steps to update the client to call the GetStatus method.

1.   Open Program.cs in the ConsoleApplicationClient project and replace the code that calls the GetData method and outputs the results with the following:

            // Call the GetData method on the workflow
            string status = client.GetStatus("1");
            Console.WriteLine("the status is from the status method is: " + 
status);


2.   Build the ConsoleApplicationClient project.

3.   Press F5 to run the solution. The client should access the new updated workflow, and you should see the result shown in Figure 19.10.

FIGURE 19.10 Client results after changing the Receive activity and the interface.

Client results after changing the Receive activity and the interface.

4.   Stop the console projects.

Accessing WorkflowRuntime from WorkflowServiceHost

Even though you have not interacted with the runtime, the workflows in this hour have been run by the WF runtime. The WorkflowServiceHost has managed this interaction behind the scenes. At times, however, you need more control of the way workflows are hosted. Registering events with the runtime and adding runtime services, for instance, requires access to the runtime.

In this section, you modify the ConsoleApplicationWcfWorkflowHost host application to retrieve the WorkflowRuntime from the WorkflowServiceHost. Then you register the completed and terminated events and add the tracking service. The only new code is to retrieve the WorkflowRuntime from the WorkflowServiceHost. Registering events and adding services works the same as it does when accessing the WorkflowRuntime directly.

Performing Preparatory Work

Follow the next steps to add references, using directives, and perform other prepatory work.

1.   Click the ConsoleApplicationWcfWorkflowHost project in the Solution Explorer.

2.   Add a reference to the WorkflowRuntime.

3.   Add the following using directives to Program.cs in the ConsoleApplicationWcfWorkflowHost project:

using System.Workflow.Runtime;
using System.Workflow.Runtime.Tracking;


4.   Add the following member variable below the opening class bracket:

     static string connectionString = "Initial
Catalog=WFTRackingAndPersistence;" +
            "Data Source=localhost; Integrated Security=SSPI;";


Retrieving the WorkflowRuntime

Follow the next steps to access the WF runtime from WCF using WCF’s extensibility capability. The WorkflowRuntime is retrieved from the WorkflowServiceHost.Description.Behaviors collection property. Accessing the WF runtime this way conforms to standard WCF extensibility.

1.   Add the following code below the line of code that instantiates the WorkflowServiceHost to retrieve the WorkflowRuntime from the WorkflowServiceHost type:

               // Retrieve the WorkflowRuntime from the WorkflowServiceHost
               WorkflowRuntime workflowRuntime =

                      selfWorkflowHost.Description.Behaviors.Find
                      <WorkflowRuntimeBehavior>( ).WorkflowRuntime;


2.   Add the following code below the code you just added to register the events and add runtime services:

            // Register the workflow events
            workflowRuntime.WorkflowCompleted +=
                new EventHandler<WorkflowCompletedEventArgs>
                    (workflowRuntime_WorkflowCompleted);
            workflowRuntime.WorkflowTerminated +=
                new EventHandler<WorkflowTerminatedEventArgs>
                    (workflowRuntime_WorkflowTerminated);

            // Add the sql tracking service to the runtime
            SqlTrackingService sts = new
SqlTrackingService(connectionString);
            workflowRuntime.AddService(sts);


3.   Add the following handlers below the Main method:

        static void workflowRuntime_WorkflowCompleted
    (object sender, WorkflowCompletedEventArgs e)
        {
            Console.WriteLine("WorkflowServiceHost accessed runtime
completed hander. ");
        }

        static void workflowRuntime_WorkflowTerminated
            (object sender, WorkflowTerminatedEventArgs e)
        {
            Console.WriteLine("Workflow terminated");
        }


4.   Build the ConsoleApplicationWcfWorkflowHost project.

Running the Project

Follow the next steps to run the project, and ensure that the WorkflowCompleted handler emitted the content specified in it to the console.

1.   Press F5 to run the solution.

2.   Go to the host console, and you should see that the workflow completed handler was invoked as shown in Figure 19.11.

FIGURE 19.11 WorkflowCompleted handler called from WorkflowServiceHost hosted WorkflowRuntime.

WorkflowCompleted handler called from WorkflowServiceHost hosted WorkflowRuntime.

3.   If you would like, run the WorkflowMonitor (Hour 5, “Creating an Escalation Workflow”) or look in the database directly to see that the workflow is being tracked.

4.   Stop both the client and host projects.

Connecting to a WCF Endpoint from WF

Now it is time to use the Send activity to access a workflow. The workflow with the Send activity will replace the current client that calls the workflow and receives its results. When you use the Send activity to invoke a service, the workflow does not have to run under a WCF host. Moreover, if there are no Receive activities on the workflow, it must not be hosted by the WorkflowServiceHost. Therefore, we must host our new client workflow in the standard WF runtime, where it will access the host workflow that determines the status.

The client workflow accesses the host workflow via its address, bindings, and contract. It can access any endpoint capable of supporting these characteristics. Other possible endpoints include standard WCF services not enabled by workflows and standard web services.

Before continuing, the major Send activity properties are the ServiceOperationInfo property that binds the Send activity to an interface, just as it does for the Receive activity, and the ChannelToken property that points to the EndpointName attribute in the client section of the App.config file. AfterSend and BeforeSend are handlers that can be called before and after the message is sent. Logging and preparation are common uses of these handlers.

Updating the Workflow

In this section, you add a new workflow and configure it to use the Send activity.

Performing Preliminary Setup

Follow the next steps to create a Sequential Workflow Console Application project to host the client workflow.

1.   Add a new Sequential Workflow Console Application project and name it ClientWorkflow.

2.   Add code to pause the host.

Modeling the Workflow

The workflow will initialize a variable in the initial Code activity that will be passed to the service as a parameter. The second Code activity will then emit the results returned from the service to the console.

Follow the next steps to add the activities to the workflow.

1.   Open Workflow1 in the ClientWorkflow project in design mode.

2.   Add a Code activity to the workflow.

3.   Add a Send activity to the workflow below the Code activity.

4.   Add a Code activity below the Send activity.

Configuring the Send Activity Step 1

Follow the next steps to configure the ServiceOperationInfo property, which is almost the same as configuring this property on the Receive activity. You will also bind a few properties to send a value to and receive a value from the service.

1.   Add a reference to the ContractsAndWorkflows project.

2.   Click the Send activity. Then click its ServiceOperationInfo property and click the ellipsis.

3.   The Choose Operation dialog is spawned.

4.   Select the Import icon in the upper-right corner.

5.   The Browse and Select a .NET Type dialog is displayed. Expand the ContractsAndWorkflows project, and choose IWorkflow1 in the middle pane. Click OK.

6.   You are returned to the Choose Operation dialog. The GetStatus operation is selected because it is the only operation. Click OK to exit.

7.   Bind the ReturnValue property to a new field. Click the ReturnValue property. Click the ellipsis, select the Bind to a New Member tab, select the Create Field option button, name it StatusValueReturned, and click OK. This stores the status returned from the called workflow.

8.   Bind the customer property to a new field. Click the value property. Click the ellipsis, select the Bind to a New Member tab, select the Create Field option button, name it CustomerValueSent, and click OK.

Configuring the Send Activity Step 2: The ChannelToken Property

The ChannelToken property holds the endpoint name of the service the Send activity will invoke. Follow the next steps to populate it with the endpoint name attribute from the client section of the App.config file. This maps the client service parameters (address, binding, and contract) to the Send activity. This is needed because multiple client services may be in one config file. We will use the generated name here, the binding plus the contract, but you are free to change it to a more meaningful name, such as OrderServiceEndpoint.

1.   Copy the App.Config file from the ConsoleApplicationClient project to the ClientWorkflow project.

2.   Open the App.config file in the ClientWorkflow project. Go down to the client section.

3.   Copy the text between the quotes in the name attribute in the client endpoint element (WSHttpContextBinding_IWorkflow1) and paste it in NotePad for use in a couple of steps.

4.   The contract attribute in the App.config file must include the project name. To do so, prepend ContractsAndWorkflows to the contract attribute. It is directly to the left of the name attribute. It should look like this when complete:

contract="ContractsAndWorkflows.IWorkflow1"


5.   Click the ChannelToken property. Enter TheChannelToUse. Then press Enter.

6.   Click the + next to the ChannelToken property. Paste the following text you copied from the App.config file in the EndpointName property:

WSHttpContextBinding_IWorkflow1


7.   Click the drop-down in the OwnerActivityName property and select Workflow1.

Configuring the Code Activities

Follow the next steps to update the Code activities handlers.

1.   Double-click the first Code activity and add the following code to its handler:

            CustomerValueSent = "1";


2.   Double-click the second Code activity and add the following code to its handler:

            Console.WriteLine("The service returns the following: " +
StatusValueReturned);


3.   Build the ClientWorkflow project.

Running the Workflow Client

Follow the next steps to reconfigure the projects to start in the correct order. Then run the solution and the host will return the status to the workflow client.

1.   Right-click the solution in the Solution Explorer, select Properties, and click the plus sign to expand Common Properties. Select Startup Project and select the Multiple Startup projects option in the middle of the dialog. Select the ConsoleApplicationClient project in the list of projects, click the arrow to the right of it, and select None from the drop-down. Now set the ClientWorkflow project to start. Then reorder the projects and make sure the ConsoleApplicationWcfWorkflowHost project is first in the list.

2.   Press F5 to start the solution; you should see the results shown in Figure 19.12 in the client host Window:

FIGURE 19.12 Workflow client talk to WCF host results.

Workflow client talk to WCF host results.

Summary

In this hour you learned that WCF is complementary to WF. The first is the endpoint and latter the logic. It allows endpoints to be instantiated and called securely, reliably, and at optimum speed. WF can supply application logic and long-running support to WCF endpoints. Alternatively, WF can call out to WCF endpoints. This synergy is likely to increase, with WCF becoming WF’s de facto host.

Workshop

Quiz

1.

What three elements do WCF endpoints contain?

2.

What are the primary functions WCF supplies?

3.

What two functions does WCF provide WF? And why use WCF for these functions?

4.

What is the WorkflowServiceHost type used for?

5.

What are the two .NET 3.5 WCF-centric activities, and what is their purpose?

6.

What are some reasons to retrieve the WorkflowRuntime type from the WorkflowServiceHost type?

7.

How do you specify that a service is a WCF contract and that an operation is a WCF operation?

8.

What is the SvcUtil used for?

Answers

1.

Address, binding, and contract.

2.

A single unified design-time and runtime experience for building “any” kind of distributed application and the ability to abstract protocols, security, and other operational entities from the service.

3.

The ability to host/expose a workflow as a WCF service and to call out to services. WCF alleviates WF from having to build connectivity infrastructure when called by services and calling out to services.

4.

To host WF workflows in WCF.

5.

The Send and Receive activities. The Send activity calls out to services or endpoints from a workflow. The Receive activity permits a workflow to receive calls from services or endpoints.

6.

The general reason is to have more control of the runtime. Specific examples are to register events and add runtime services to the runtime.

7.

Attribute the service with [ServiceContract] and the [OperationContract].

8.

To create a proxy for the client to call a WCF endpoint and to create the App.config file for the client.

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

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