Published
Thursday, April 26, 2007 9:12 AM
by
mtaulty
I spent my first few minutes trying to understand the Workflow changes in Beta 1 of "Orcas" today. So far, what I'm aware of is that there are a couple of new activities called Send and Receive which couple Workflow to WCF rather than just ASMX web services which is what we had in V3.0 (although it's not too hard to use external communication services to make it work with WCF) and there's also a new class called WorkflowServiceHost which (at least logically) seems to do something like;
- Derive from ServiceHostBase and, therefore, "is" a ServiceHost for WCF
- Aggregate at least one (maybe more? not sure!) instances of the WorkflowRuntime for us.
- Provides a whole bunch of WCF infrastructure around what seems to be called a ContextToken which looks like a bunch of state used to identity a particular Receive activity inside a particular Workflow instance. It looks like a ContextToken can be passed around either as an HTTP Cookie (which is what got done for ASMX web services if I remember correctly) or as a SOAP header.
I couldn't find any docs or samples (although I did find samples for the Feb CTP which helped quite a bit) so I did quite a bit of poking around with Reflector which I think just confused me massively like it often does.
The new (green?) bits seem to live in an assembly called System.WorkflowServices.dll and there's quite a lot of WCF infrastructure in there relating to this idea of the ContextToken. I don't pretend to understand 95% of it but I saw things like;
- wsHttpContextBinding, netTcpContextBinding (i.e. presumably new bindings to add this token support to existing transports/protocols)
- ContextBindingElement - presumably the binding element you add into your binding if you want a context-ful channel
- ContextChanneListener, ContextChannelFactory, ContextXXXXXChannel (XXXXXX == Reply and a few more)
- SqlPersistenceProvider?
- I haven't figured this out yet but I assume this is some SQL store where we can persist the various active WCF endpoints at the point where the host process gets cycled or similar so that we can bring them back up at a later point?
Anyway, that's all just "goo". In terms of trying to get something working I first went and built a WCF Service Library called WcfServiceLibrary1 :-) which has my contract in it;
[ServiceContract]
public interface IAddTwoNumbers
{
[OperationContract]
int GetData(int n1, int n2);
}
I then went off to build a Workflow...the toolbox has the 2 new WCF activities on it;
I dragged a ReceiveActivity to my design surface.
Brought up the properties window on it;
Looked into the "ServiceOperationInfo" property and imported my WCF contract previously declared;
Bound up the incoming and outgoing data on the service operation to newly created properties on my Workflow;
And then added a code activity in order to add N1 + N2 and stick the result into Result. It's nice that the Receive Activity is a composite Activity in that you don't have that "pairing" to do that you did with the ASMX Activities.
With that in place it's time to try hosting the Workflow. I found this a bit odd. The hosting code I used looked like;
WorkflowServiceHost host = new WorkflowServiceHost(typeof(Workflow1));
host.Open();
Console.ReadLine();
So that's ok but it needs some configuration and I provided;
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WorkflowLibrary1.Workflow1"
behaviorConfiguration="serviceBehaviour">
<endpoint address="http://localhost:8100/foo" binding="wsHttpContextBinding"
contract="WcfServiceLibrary1.IAddTwoNumbers"
bindingConfiguration="serviceConfig">
</endpoint>
</service>
</services>
<bindings>
<wsHttpContextBinding>
<binding name="serviceConfig">
<security mode="None"/>
</binding>
</wsHttpContextBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehaviour">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8100/foo"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
and with that in place I can run up the code and I can get a WSDL document out of the service so I was feeling fairly happy about that.
At this point, it's time to build a client so a quick File->New Project to build a console application. I pointed it at the WSDL that my service is generating and produced a proxy using the slightly nicer "Add Service Reference" dialog;
and "wrote" the lines of code to call the service;
ProxyCode.AddTwoNumbersClient client =
new ProxyCode.AddTwoNumbersClient();
// Why did I call this GetData?
Console.WriteLine(client.GetData(100, 200));
and the service got called :-) Success!
Now, there's a lot of things that I haven't worked out here such as;
- How to do a Send :-)
- How to use the ContextToken to differentiate between different Receives and perform some sort of correlation (I think it's likely to be "automatic").
- Can we do duplex?
- How do we host in IIS?
- How do we make use of the persistence stuff to ensure that the Receive still occurs if the hosting process gets cycled and so on.
- What happens if you have more than 1 Workflow type sitting in your process. Does that mean multiple WorkflowServiceHosts?
- etc.
So I'll continue to explore and see what I can work out.