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:foo</a:Action>

    <a:MessageID>urn:uuid:c7c03178-fa84-400e-8673-ad1ed28f0f79</a:MessageID>

    <a:ReplyTo>

      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a: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.