WF and WCF Integration in "Orcas" - Part 1 - Workflow Enabled Services
WF and WCF Integration in "Orcas" - Part 1 - Workflow Enabled Services
I've been waiting for a long time for Beta 1 of Visual Studio "Orcas" to get to play with the WCF and WF Integration. Back in Tech Ed 2006, Dennis Pilarinos talked about the fact that v1 of Windows Workflow Foundation will only enable developers to expose workflows as ASMX Web Services, and v2 will contain the Windows Communication Foundation Integration Activities (Send and Receive).
So, right after I downloaded Beta 1 I build a simple workflow that exposed via WCF Service (a.k.a "Workflow Enabled Service"). This post will show the steps I made in order to do this. You are welcome to use this post as a getting-started-guide.
Creating a Service Contract
Create a new class library called WCFWFIntegration.ServiceContracts.
Add references to System.ServiceModel and System.Runtime.Serialization.
Create the service contract you want to use. For demo purposes, I created the following Service Contract:
[ServiceContract]
public interface IOrdersService
{
[OperationContract]
OrderInfo CreateOrder(OrderData orderData);
}
that uses the following Data Contracts and Fault Contract.
[DataContract]
public class OrderData
{
private int amount;
private string currency;
[DataMember]
public int Amount
{
get { return amount; }
set { amount = value; }
}
[DataMember]
public string Currency
{
get { return currency; }
set { currency = value; }
}
}
[DataContract]
public class OrderInfo
{
private int id;
[DataMember]
public int Id
{
get { return id; }
set { id = value; }
}
}
[DataContract]
public class FaultDataContract
{
private int id;
[DataMember]
public int ErrorId
{
get { return id; }
set { id = value; }
}
private string message;
public string ErrorMessage
{
get { return message; }
set { message = value; }
}
}
Build the project and make sure it compiles.
Creating the Workflow that implements a Service Operation
Add a new project pf type Sequential Workflow Library and name if WCFWFIntegration.Workflows.
Rename the exiting workflow file name to CreateOrderWorkflow. This will also change the name of the class to CreateOrderWorkflow.
Add a reference to the WCFWFIntegration.ServiceContracts project.
Notice that the toolbox contains a new category called Windows Workflow v3.5. This category contains the new Send and Receive activities that implement the integration.

Drag the ReceiveActivity from the toolbox into the design surface. This will add the new activity to the workflow.
Notice that the ReceiveActivity is a composite activity and therefore can contain child activities. This activity executes when a WCF Service Operation is executed and completes when the operation returns a value or a fault. That said, all the service business logic should be implemented as child activities in this activity.
If you go to the properties pane and display the properties of the Receive Activity, you'll notice the ServiceOperationInfo property is marked as erroneous. This means that this ReceiveActivity is not bounded to any Service Operation.
If you click the error sign of this property the Choose Operation dialog will show. You can create a new Service Contract using this Dialog using the Add Contract button, or you can use the Import button to use an exiting contract.
After you choose the Service Contract and the Operation to implement, the input and output parameters will be added to the properties pane. You can bind them to new fields in the workflow.
The ReceiveActivity has some additional properties you should know about:
CanCreateInstance - Indicates whether this Receive activity starts a new workflow instance or uses an existing one. Similar to the IsActivating property of WebServiceInput activity.
FaultMessage - If the service returns a Fault Message, it will return the fault message object specified here.
OperationValidation - This is an event Handler. You can handle this event if you want to validate your parameters, perform security checks and so on.
Since this is the initiating service call, you should set the CanCreateInstance property to True.
Make sure to bind the return value to a new field of type OrderInfo.
Now, you can insert any additional activities as child activities of this ReceiveActivity.
Build this project and make sure if compiles. If you run into an error about missing SMDiagnostics.dll, you can remove the reference to this assembly from the project. This should be solved in later releases.
Hosting the Workflow Service
Create a new Console Application and name it WCFWFIntegration.Host.
Add references to System.ServiceModel and System.WorkflowServices which is the new assembly that contain all the integration components.
Add reference to the Workflow assemblies: System.Workflow.Runtime, System.Workflow.Activities and System.Workflow.ComponentModel.
Add references to the WCFWFIntegration.ServiceContracts and the WCFWFIntegration.Workflows projects.
Use this code to implement this Main method of this application:
WorkflowServiceHost serviceHost = new WorkflowServiceHost(typeof(CreateOrderWorkflow));
WSHttpContextBinding contextBinding = new WSHttpContextBinding();
serviceHost.AddServiceEndpoint(typeof(IOrdersService), contextBinding, "http://localhost:8080/OrdersService");
serviceHost.Open();
Console.WriteLine("Service is listening. Press any key to close...");
Console.ReadLine();
serviceHost.Close();
There are few things you should notice about this code:
1. Instead of using ServiceHost class in order to host a WCF Service, I used WorkflowServiceHost class. This host implements the mechanism of invoking workflows an services. If you look through this type's properties during debug, you'll notice that this service description contain ServiceType = null.
2. I used the WSHttpContextBinding as the binding for calling this service. As similar to standard HTTP binding that enabled cookies, this binding also keeps the context of the service calls. This allows us not to pass the WorkflowInstanceID to every service call explicitly.
Now, you can set the startup project to be the WCFWFIntegration.Host project and run to see if it is running OK.
Creating a Test Client
I still haven't managed to expose any Metadata Exchange endpoint for this service, since there is not actual service that implements this behavior. (Any Idea?) So, I had to couldn't add a service reference and use the generated proxy.
Create a new Console Application and name it WCFWFIntegration.Client.
Add references to the System.ServiceModel, System.WorkflowServices.
Add a reference to the WCFWFIntegration.ServiceContracts project.
Implement the Main method of this application using the following code:
Binding binding = new WSHttpContextBinding();
ChannelFactory<IOrdersService> factory = new ChannelFactory<IOrdersService>(binding, "http://localhost:8080/OrdersService");
IOrdersService proxy = factory.CreateChannel();
OrderData data = new OrderData();
data.Amount = 3;
data.Currency = "USD";
OrderInfo info = proxy.Create(data);
Console.WriteLine(info.Id);
Run both Host and Client projects and see how the client invokes the service operation implemented by a workflow.
You can download a sample project that shows the above integration.
I hope this post gives you a little sense about Workflow Enabled Services in Visual Studio "Orcas". In the next post I'll talk about Service Enabled Workflows. Stay tuned...
Feedback so far
1. I have a problem with the usage of WSHttpContextBinding. This means that a service consumer should know about the fact that this service operation is implemented with workflow.
2. When adding a new class to a workflow library, the file is added with a using directive to the System.Linq namespace. Since the workflow library doesn't contain any reference to this project, the project will not complie.
3. There is a reference to SMDiagnotics.dll in the workflow project that can make problems building this kind of projects.
4. The activities in the designer are wider than they were in Visual Studio 2005. This allows us to name the activities with names that are longer than 9 characters without breaking a line. Although this is a tiny thing, I know it will help me during presentations.
I will provide more feedback about this integration in the future.
Enjoy!