DCSIMG
WF and WCF Integration in "Orcas" - Part 2 - Service Enabled Workflows - Guy Burstein's Blog

Guy Burstein's Blog

Developer Evangelist @ Microsoft

News

Guy Burstein The Bu

Disclaimer
Postings are provided 'As Is' with no warranties and confer no rights.

Guy Burstein LinkedIn Profile

WF and WCF Integration in "Orcas" - Part 2 - Service Enabled Workflows

WF and WCF Integration in "Orcas" - Part 2 - Service Enabled Workflows

This is the second post I am talking about the Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Integration in Visual Studio "Orcas". These posts are being written in "Orcas" Beta 1 time, so the components, namespaces and properties may change in the future, but the principles should stay pretty much the same.

In the previous post, I've talked about Workflow Enabled Services. I have implemented a WCF Service with a workflow and hosted it. This post I am going to talk about Service Enabled Workflows. By this name I mean that a workflow which as part of its logic there is a Service call. This class will be done using the SendActivity that is shown in the first time in "Orcas" Beta 1.

Building a Simple WCF Service

To begin with, build a simple WCF Service. You can use the WCFWFIntegration.ServiceContracts from my previous post instructions to copy the OrderData, OrderInfo and FaultDataContract Data Contracts, and also copy the service contract itself.

[ServiceContract]

public interface IOrdersService

    [OperationContract]

    OrderInfo CreateOrder(OrderData orderData);

}

 

[DataContract]

public class OrderData { ... }

 

[DataContract]

public class OrderInfo { ... }

 

[DataContract]

public class FaultDataContract { ... }

To implement this service, create a new Class Library project and name it WCFWFIntegration.Services.
Add references to System.ServiceModel and WCFWFIntegration.ServiceContracts project.
Implement the service. For demo purposes, I had a random logic in the service:

public class OrdersService : IOrdersService

{

    public OrderInfo Create(OrderData orderData)

    {

        Random rnd = new Random();

        OrderInfo info = new OrderInfo();

        info.OrderId = rnd.Next(1, 10);

        return info;

    }

}

To host this service, create a Console Application and name if WCFWFIntegration.Host.
Add references to System.ServiceModel and WCFWFIntegration.ServiceContracts project.
Use the following code snippet to host the service and expose it via Http endpoint:

ServiceHost serviceHost = new ServiceHost(typeof(OrdersService));

Binding binding = new WSHttpBinding();

serviceHost.AddServiceEndpoint(typeof(IOrdersService), binding, "http://localhost:8080/OrdersService");

serviceHost.Open();

 

Console.WriteLine("Service is listening. Press any key to close...");

Console.ReadLine();

serviceHost.Close();

Make sure the project builds and runs successfully.

Creating a Workflow Client

Create a new Sequential Workflow Console Application and name if WCFWFIntegration.WFClient.
Add references to WCFWFIntegration.ServiceContracts project.

Open the workflow in the designer and drag a SendActivity from the Toolbox.

WF and WCF Integration Orcas Service Enabled Workflows

This activity invokes service calls as part of a workflow. If you take a look at this activity properties you'll see that the ServiceOperationInfo property is erroneous.

WF and WCF Integration Orcas Service Enabled Workflows

Click this property to assign a Service Operation to invoke. This will show the Choose Service Operation Dialog that lets you import an existing Service Contract and choose an operation to invoke.

WF and WCF Integration Orcas Service Enabled Workflows

Use the import button to import the IOrdersService contract and select the Create operation. You can see some of the operation attributes in the lower part of the dialog.

After you confirmed the operation selection, the operation parameters will be dynamically added to the property pane of the SendActivity, and the ChannelToken property (more details later) will become mandatory. Bind it to a new field in your workflow. You should also bind the operation in and out parameters to members of the workflow.

The AfterResponse and BeforeSend properties are events that the activity raises when it executes. You can handle these events and add your logic before and after the call to the service is made.

The ChannelToken property holds the information the SendActivity requires in order to create a channel. It has a EndpointNameName and OwnerActivityName properties. You should set these properties to values that fits the client endpoint configuration required to communicate with the service.

In order to set these properties, you have to write some code. I used a CodeActivity just before the SendActivity to do this: 

this.channelToken.EndpointName = "CreateOrder";

this.channelToken.Name = "CreateOrderToken";

this.channelToken.OwnerActivityName = this.sendActivity1.Name;

while the configuration for the CreateOrder endpoint is:

<configuration>

  <system.serviceModel>

    <client>

      <endpoint name="CreateOrder"

                address ="http://localhost:8080/OrdersService"

                binding ="wsHttpBinding"

                contract ="Bursteg.Samples.WCFWFIntegration.ServiceContracts.IOrdersService"/>

    </client>

  </system.serviceModel>

</configuration>

Run both Host and WFClient projects and see how the Workflow client invokes the service operation.

In this post I showed how to create a client with Windows Workflow Foundation that invokes a WCF Service. This is an example for a Service Enabled Workflow. You can download a sample project that shows this integration.

Feedback So Far

1. After choosing a service operation, the operation parameters are added to the properties pane. I can bind the parameters, but not the fault contracts. How can I handle exceptions and receive any faults?

2. Debugging is problematic. I cannot debug the workflow that contains the SendActivity. Is it a known issue, or have I done something wrong?

3. I had to manually configure the ChannelToken property values. Is there any more convenient way to do it? Any designer?

4. For some reason, I got an exception saying that one of my data contracts was not marked as serializable. I had to add the Serializable attribute next to the DataContract attribute in order to get things work.

5. The Choose Service Operation dialog allows importing an existing Service Contract. I think it should be able to infer a service definition from its metadata, just like "Add Service Reference", and like the Web Service Activities do.

I will provide more feedback about this integration in the future.

Enjoy!

Comments

No Comments