Note: Cross posted from
Sajay.
Permalink Building a workflow service using 4.0 gives a very neat set of capabilities from both WF and WCF. Similar to WCF we can fully define a workflow either in code or otherwise just using Xaml. Here I chose a fully code based approach. If you just want the source you can download it here.
The Service Contract
We generally can take a workflow first approach or a contract first. To keep things simple, I have a very bare service contract as shown below.
| [ServiceContract] interface IService1 { [OperationContract] void GetData(); } |
I also hold on to the contract description. This is just convenience and to avoid some constants like service name etc.
| ContractDescription description = ContractDescription.GetContract(typeof(IService1)); |
The Operation
The idea here is to build the service bottom up from operation we need to perform. I can think of my workflow as composition of activities. The functionality of my service is quite simple here. All I do is write a message to the console. So the body of my operation will look something like this.
| new WriteLine { TextWriter = Console.Out, Text ="Hello Workflow." }, |
The Implementation
Now I need to make this an operation. An operation has an associated message exchange pattern, commonly referred to as MEP. In my case it's a simple receive reply pattern. This means I have to compose my work in between a Receive and a SendReply. I am also going to tie this all up in Sequence as shown below.
| Sequence sequence = new Sequence { Activities = { receive, new WriteLine { TextWriter = Console.Out, Text ="Hello Workflow." }, reply } }; |
The Message Exchange
The next thing is to lay out my Receive and Reply which will define the wire format of the messages.
- The receive needs to know the operation that the client can invoke. Also I need to make sure that the workflow can be instantiated by this particular operation. For this I need to set the CanCreateInstance property. Also the serializer used by default is the DataContractSerializer.
| Receive receive = new Receive { OperationName = description.Operations[0].Name, CanCreateInstance = true }; |
- The Reply is send back to the client using my SendReply activity. This reply is a part of a conversation and it needs to know which request it would respond to. I can do this by pointing the SendReply to the instance of the corresponding Receive. Also I don't have any data here so it is an empty parameter list. (the operation is not Messages contract based in my case but this is generally a better option for more control and performance.)
| SendReply reply = new SendReply { Request = receive, Content = new SendParametersContent { } }; |
- I now need to define the workflow service which would hold this Sequence and also need to specify the full name of the service definition. For this I can use the description object to get the name, namespace etc.
| WorkflowService serviceDefinition = new WorkflowService { Body = sequence, Name = XName.Get(description.Name, description.Namespace) }; |
The Host
The next step is to give this definition to the workflow service host so that it can start the service. Here I self host the workflow as shown below.
| WorkflowServiceHost host = new WorkflowServiceHost(serviceDefinition, new Uri("http://localhost:8080")); host.AddServiceEndpoint(serviceDefinition.Name, new BasicHttpBinding(), ""); host.Open(); |
The Test
Finally I can test the workflow using a simple proxy.
| ChannelFactory<IService1> cf = new ChannelFactory<IService1>(new BasicHttpBinding(), "http://localhost:8080"); IService1 proxy = cf.CreateChannel(); proxy.GetData(); ((IChannel)proxy).Close(); |