Silver .NET 3.5 and Context Management

Last week I attended a partner event here at microsoft campus to help one of our customers with architecting his application using Workflow Services(WF-WCF bridging) which is part of .NET 3.5 Orcas.

One of the main focus points of our discussions was being able to make my customer understand about context management. Now, though this is very similar to .NET 3.0 correlation, I think a good look at it from the WCF perspecive would be a good value add.

When a workflow service sends a response back to a client it sends back its context in the header. This context is nothing but the Workflow Instance Id(though there are some complicated cases with more into this context. We will look at it later). The client saves this context as part of applying it to its channel. The channel being cached for its communication to the service next time.

Things get interesting when a client invokes a WF service which invoked another service and now everyone wants to talk to each other. This can be done using context being passed around from one place to another either persisted in a file or even in a Db. The SDK has a great sample of how to persist the context into a file and then depersisting it back to apply it to a new client channel. The project is WorkflowServiceUtility referenced in the CalculatorClient sample(The service for this client being StateMachineWorkflowService). As you would see it is very simple. Context is a just a dictionary object in the end with a key value pair. In simple cases with just one key for Workflow Instance Id.

The other great sample which leverages the power of Silver is the Conversations sample. This is one sample which I think every WF Services user should understand in and out. It is a case where it is more of a peer to peer communication and when you initiate a coversation with a service you pass in your context as one of the operation parameters. This way the other party knows how he can talk to you if need be. Check a sample contract there -

[ServiceContract]

public interface IOrder

{

[OperationContract(IsInitiating=true)]

string SubmitOrder(PurchaseOrder po, IDictionary<XmlQualifiedName,string> context);

}

Now when the Supplier wants to GetQuotes from the Shippers, all of them abiding by the same contract and operation in a parallel activity we do something very simple. Each parallel branch's supplier GetQuotes' Send Activity passes in its context to the respective shipper. How does the shipper get that context? Check the BeforeSend event handler. Note that the context for each branch is different. This is it. Now the Shipper Workflows know the contexts on which they have to respond back to the Supplier individual branches.The Shipper's receive passes in the context to its send later in the workflow. There is one more thing to the magic happening around here which I think is of great value. The Receive Activities within the Supplier parallel branches' owner activity. It is the parallel activity. In this example it could have been the individual branches or even the root workflow as well. But imagine, where the send and receive are with a parallel which in itself is within a While. In such cases parallel activity being the owner is necessary to pass in the right context. Also this is where the context carries something more than just the workflow instance Id. It also has the context for parallel tagged along.

This is it from my side. Hope this helps when you start doing all sorts of crazy stuff for Workflow Services/WCF communications. Another great start point to understand Workflow services in-depth would be this presentation. Let me know if you have any questions and I will try to answer them as early as possible.

Thanks,

Kushal.

P.S. There is one other important thing I think I should warn you since I just remembered this problem I faced with my customer when we were prototyping his solution.

The first time a client calls a silver service a new Workflow instance is created only if the silver service(Receive Activity) has CanCreatInstance marked as True. This way the channel is established with the response header haveing the workflow instance Id. Now since this channel is cached the next response during the conversation would not again have the Instance Id/Context passed back. Contexts are passed only on per channel basis and not per message. Hope this helps!