Supported Message Exchange Scenarios
Workflow Services support a subset of the message exchange scenarios defined in Windows Communication Foundation (WCF). The two supported scenarios are one-way send and request/response. In a one-way send scenario, the client does not expect a response when calling an operation on the workflow service. It simply calls the operation and proceeds with the rest of its execution. In a request/response scenario, the client expects a response from the workflow service and blocks the main execution thread until that response is received. As noted in these scenarios, the client initiates all message exchanges with the workflow service.
Duplex communication can be achieved in two ways. The first way is to use duplex contracts like a normal WCF service to establish session IDs that will be used for asynchronous communication. Unfortunately, because session IDs are tied directly to the duplex channel, whenever the channel is destroyed, the notion of using session IDs as a means of establishing a context between client and service is no longer possible. The second way to enable duplex communication is through the use of correlated contracts that communicate through independent channels. These contracts pass context ID information in their initial operation invocation and the operation state can be persisted like any other workflow service. By using correlated one-way contracts, the context ID is stored at the application layer, so if either the client or the service has been restarted, it can resume from its last persisted state. This is the preferred method of duplex communication for workflow services.
As a best practice, you should perform one synchronous request/response operation with the service before engaging in asynchronous communication. This exchange will allow the client and service to establish a context that can be used in future operation invocations.
This section describes how workflow and durable services use contexts to correlate messages between services and clients. After an initial request/response operation, the client receives a context from the service and provides that same context on all future messages to the service for the lifetime of that message exchange. The context is opaque to the client, and provided only to maintain communications with an established message exchange with a given service instance. After the context is established, it can only be modified by an incoming message from the service.
|In the case of duplex scenarios, the service sends the context back as a context header to the client as a part of the first message sent from the service to the client and not necessarily as the response to the first request from the client.|
On the service side, an instance of the channel is responsible for converting the context supplied by the client in the form of a SOAP header on incoming messages to a ContextMessageProperty type. The ContextMessageProperty can then be consumed by the application layer or channels up in the stack. Service-side channels also allow the application layer to specify a new context value to be propagated back to the client.
By maintaining this context at the application layer, the original channel can be torn down and a new channel established. While the context exchange mechanism is provided by the channel, the actual context can be provided and recovered by the application layer (on both client and service).
For service endpoints that use an HTTP transport and clients that agree to allow the use of HTTP cookies, the HttpCookie mechanism can be used to exchange the application context. The context exchange protocol allows the client channel to accept a context supplied by a service and apply it on all subsequent requests so that the service can receive requests sent over the same client channel instance. The context exchange protocol also provides a SOAP-based equivalent of the feature offered by HTTP cookies at the transport layer.
|Clients that are workflow-based and use a SendActivity activity to communicate with a durable service or workflow service must use a binding that contains ContextBindingElement to exchange the context between client and service, or provide some other correlation channel that integrates with ContextMessageProperty.|
The SOAP header is a wsc:Context SOAP header used to represent the context information. Context header schema allows for any number of child elements, each with string content. This allows the corresponding message property representing the context to use a convenient dictionary that maps an XML qualified name (the child element name and namespace in the wsc:Context header) to a string value (the text value of the child element in the wsc:Context header). The wsc:Context header is therefore required to be digitally signed at either SOAP or transport level when the binding offers message protection capability.
Getting and Setting the Context
The ContextMessageProperty described in the previous section is a message property used for communicating the context between the application layer and the channel layer on either the client or the service side. If the context is established at the channel layer, all incoming messages on the client and the service will have this property attached by the context channel. If the context is attached to an outgoing message on the client or the service at the application layer, the context stored at the channel layer will be replaced by the one represented by the ContextMessageProperty.
In addition to the ContextMessageProperty, which can be used on the client or the service side, on the client side, the current context can be obtained or a new context can be set on channel instance using IContextManager as shown in the following examples:
IDictionary<string, string> context; IContextManager cm = ClientProxy.InnerChannel.GetProperty<IContextManager>(); if (cm != null) context = cm.GetContext();
IContextManager cm = ClientProxy.InnerChannel.GetProperty<IContextManager>(); if (cm != null) context = cm.SetContext();
|The ClientProxy object is an example of an instance of the proxy class that is generated by svcutil to make operation invocations on a service.|