Here
I talked about couple of approaches to enable durable duplex messaging in .Net
3.5.
.NET 4 has added first class support for durable duplex
messaging by extending Context Exchange Protocol
to include a CallbackContext. So in addition to instanceId, a client
application can send a callback context as part of the call.
Service, upon receiving the message, will start the long
running work and when it needs to callback to client, it can simply use the address
from the callback context.
From API perspective – a
new property “ClientCallbackAddress” is added to
ContextBindingElement. This property is also exposed on some higher level
bindings like wsHttpContextBinding.
A new CallbackContextMessageProperty
is also added to manipulate callback context from the application code.
<bindings>
<wsHttpContextBinding>
<binding name="noSec" clientCallbackAddress="http://localhost:7080">
<security mode="None"/>
binding>
wsHttpContextBinding>
bindings>
Any messages sent using above binding will have a callback
context attached to it. Please note callback context is only supported with
SOAP based context exchange and that’s why clientCallbackAddress property is NOT
exposed on basicHttpContextBinding as it uses HTTP cookies for context
exchange.
var cf = new ChannelFactory<IRequestChannel>(new WSHttpContextBinding("noSec"),
new EndpointAddress("http://localhost:8975/"));
var ccmp = new CallbackContextMessageProperty(new Dictionary<string,string>());
var msg = Message.CreateMessage(MessageVersion.Default, "urn:foo",
"");
msg.Properties.Add(CallbackContextMessageProperty.Name,
ccmp);
cf.CreateChannel().Request(msg);
This will produce following SOAP
envelop and you can see CallbackContext header is added in outgoing message.
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">urn:fooa:Action>
<a:MessageID>urn:uuid:c7c03178-fa84-400e-8673-ad1ed28f0f79a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymousa:Address>
a:ReplyTo>
<CallbackContext xmlns="http://schemas.microsoft.com/ws/2008/02/context">
<CallbackEndpointReference>
<a:Address>http://localhost:7080/a:Address>
<a:ReferenceParameters>
<Context xmlns="http://schemas.microsoft.com/ws/2006/05/context"/>
a:ReferenceParameters>
CallbackEndpointReference>
CallbackContext>
<a:To s:mustUnderstand="1">http://localhost:8975/a:To>
s:Header>
<s:Body>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>
s:Body>
s:Envelope>
On the server side, you can pick up the CallBackContext from
the Message Properties and use it for call-backs. So far I have shown kind of a
manual way of dealing with callback context. Workflow services in .Net 4 along
with correlation feature has really simplified all this and you never need to muck
with CallbackContextMessageProperty
etc.
In your client workflow, simply make sure you have an active correlation handle on your send activity and then use a binding capable
of transporting callback context (e.g. wsHttpContextBinding mentioned earlier)
In your server side workflow, simply make sure that Receive
and Send (used for callback) activities are correlated either using implicitly
or explicit correlation and that’s it.

You don’t need to specify Endpoint Address on your
Send activity and it will automatically pick it from CallbackContext.