X

wsHttpDualBinding - a non-interoperable binding

Guest Author
Based upon a


user request
, I'll explain why


wsDualHttpBinding
(a


system-provided binding in WCF
) is not an interoperable binding. This blog

entry will explain the service endpoint code, client code, generated WSDL

and the SOAP messages exchanged based upon the

DualHttp

Binding Sample
that is bundled with the


Windows SDK
samples. This is also an update to an


earlier attempt
to explain wsDualHttpBinding.


In the sample, I replaced the default wsDualHttpBinding with

an equivalent custom binding (after removing the security) as:


<bindings>
<customBinding>
<binding name="Binding1">
<reliableSession />
<compositeDuplex />
<oneWay />
<textMessageEncoding
messageVersion="Soap12WSAddressing10"
writeEncoding="utf-8" />
<httpTransport authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
proxyAuthenticationScheme="Anonymous"
realm=""
useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>

The wsDualHttpBinding, also known as Composite Duplex

or Full Duplex Binding, provides a bi-directional communication between Client and Endpoint. In a single

direction communication, the client can invoke a set of operations on a service

and this interface is referred as primary interface in Duplex

binding. The set of operations that a service can invoke on the client is

called as callback interface.


The sample in Windows SDK is a trivial calculator service where primitive

Math operations are performed in a running session on the "primary"

interface and results are returned on the "callback" interface.


Service Endpoint Code


Let's understand the service endpoint code first. The

"primary" service endpoint interface looks like:


[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", 
SessionMode=SessionMode.Required
,CallbackContract=typeof(ICalculatorDuplexCallback))]
public interface ICalculatorDuplex
{
[OperationContract(IsOneWay=true)]
void Clear();
[OperationContract(IsOneWay = true)]
void AddTo(double n);
...
}

Three points to note in this code:


  • A duplex contract requires a session, because a

    context must be established to correlate the set of messages being

    sent between client and service. Even though this is specified using

    SessionMode=SessionMode.Required
    attribute but the default

    value of

    SessionMode=SessionMode.Allowed
    (equivalent of not

    specifying) will be sufficient as well. This is because all Duplex

    bindings in .NET maintain a transport session.


  • Callback interface is specified using

    CallbackContract attribute.


  • All the methods are declared as One-way operations

    otherwise the response can be returned on the transport back channel

    itself. The documentation on this particular binding is limited.


The "callback" interface is defined as:


public interface ICalculatorDuplexCallback
{
[OperationContract(IsOneWay = true)]
void Result(double result);
...
}

In order for a service endpoint to establish a

connection with the "callback" interface on client, a

CallbackChannel
is obtained from the OperationContext

in the implementation of the "primary" interface as:


public class CalculatorService : ICalculatorDuplex
{
double result;
ICalculatorDuplexCallback callback = null;
public CalculatorService()
{
result = 0.0D;
callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
}

Another variable is initialized to return the running

result. The implementation of each method in the "primary" interface

then invokes a method on the "callback" interface to return the running

result as:


public void AddTo(double n)
{
result += n;callback.Result(result);
}

Generated WSDL


Now let's look at the generated WSDL fragments. The

policy assertion elements are:


<wsp:All>
<wsrm:RMAssertion xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm/policy">
<wsrm:InactivityTimeout Milliseconds="600000" />
<wsrm:AcknowledgementInterval Milliseconds="200" />
</wsrm:RMAssertion>
<cdp:CompositeDuplex xmlns:cdp="http://schemas.microsoft.com/net/2006/06/duplex" />
<ow:OneWay xmlns:ow="http://schemas.microsoft.com/ws/2005/05/routing/policy" />
<wsaw:UsingAddressing />
</wsp:All>

The wsrm:RMAssertion

and wsaw:UsingAddressing elements are bound to a known

namespace and their behavior is

clearly

documented
. However the specification of cdp:CompositeDuplex

and ow:OneWay elements are unclear at this time. This does

not allow any WSDL-based interoperability whenever these elements are

included.

All methods from the "primary"

and the "callback" interface are generated in one wsdl:portType.

The methods from the "primary" interface are generated as

One-way operations. But methods from

the "callback" interface are generated as

Notification operation.

For example, one of the methods from "callback" interface looks like:


<wsdl:operation msc:isInitiating="true" msc:isTerminating="false" name="Result">
<wsdl:output
wsaw:Action="http://Microsoft.ServiceModel.Samples/ICalculatorDuplex/Result"
message="tns:ICalculatorDuplex_Result_OutputCallbackMessage"/>
</wsdl:operation>

JAX-WS, the core of

Metro, supports only

Request-Response

and One-way operations.

This is the second place where WSDL-based interoperability will not work

with any JAX-WS-based WSDL import tool, such as


wsimport
. Moreover, the WSDL-to-Java mapping defined by the JAX-WS

specification requires each wsdl:portType map to a single Java

interface. This WSDL design pattern requires two interfaces to be generated

from a single wsdl:portType.


There are some other elements

in namespace prefix bound to "http://schemas.microsoft.com/ws/2005/12/wsdl/contract"

and their purpose is also unclear. Rest of the WSDL is pretty

straight-forward.


Client side code


On the client side, svcutil (WSDL

importing tool for .NET 3.0) generates the "primary" and "callback"

interface from the WSDL. The "callback" is implemented as:


public class CallbackHandler : ICalculatorDuplexCallback
{
public void Result(double result)
{
Console.WriteLine("Result({0})", result);
}
public void Equation(string eqn)
{
Console.WriteLine("Equation({0})", eqn);
}
}

This client instance is

initialized with the callback implementation as:


class Client
{
static void Main()
{
// Construct InstanceContext to handle messages on callback interfaceInstanceContext instanceContext = new InstanceContext(new CallbackHandler());
// Create a client with given client endpoint configuration
CalculatorDuplexClient client = new CalculatorDuplexClient(instanceContext);

And then the client invokes the

service endpoint normally as shown below:


// Call the AddTo service operation.
double value = 100.00D;
client.AddTo(value);
...

SOAP messages


Lets look at the SOAP messages

exchanged between client and endpoint now. The first call from the client to

an endpoint triggers a protocol handshake for establishing a session. The

CreateSequence protocol message looks like:


<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">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</a:Action>
<a:ReplyTo>
<a:Address>http://iamfine.sfbay.sun.com/Temporary_Listen_Addresses/bfd8c103-b0f9-4c65-9cb6-fbebb7d1517b/4e0cdb31-2451-4fb6-84b8-dc286e5f26c8</a:Address>
</a:ReplyTo>
<a:MessageID>urn:uuid:51918652-9a78-4ba3-82f5-e68ecd664d42</a:MessageID>
<a:To s:mustUnderstand="1">http://localhost:8888/</a:To>
</s:Header>
<s:Body>
<CreateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">
<AcksTo>
<a:Address>http://iamfine.sfbay.sun.com/Temporary_Listen_Addresses/bfd8c103-b0f9-4c65-9cb6-fbebb7d1517b/4e0cdb31-2451-4fb6-84b8-dc286e5f26c8</a:Address>
</AcksTo>
<Offer>
<Identifier>urn:uuid:b1116e69-f1dd-45b0-8495-129645038160</Identifier>
</Offer>
</CreateSequence>
</s:Body>
</s:Envelope>

The WCF runtime uses the Windows HTTP.SYS library to host an

endpoint at the address specified in a:ReplyTo. This address is

used for all subsequent messages sent on the callback channel. This message

is used to create a session for the "primary" interface. The message also

carries an offer, in the SOAP Body, to create a "callback" interface

session.


The CreateSequenceResponse protocol message

returns "primary" interface session identifier and also accepts the offered

"callback" session. The message looks like:


<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">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequenceResponse</a:Action>
<a:RelatesTo>urn:uuid:51918652-9a78-4ba3-82f5-e68ecd664d42</a:RelatesTo>
<a:To s:mustUnderstand="1">http://iamfine.sfbay.sun.com/Temporary_Listen_Addresses/bfd8c103-b0f9-4c65-9cb6-fbebb7d1517b/4e0cdb31-2451-4fb6-84b8-dc286e5f26c8</a:To>
</s:Header>
<s:Body>
<CreateSequenceResponse xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">
<Identifier>urn:uuid:d483898c-4bd3-4077-ba04-07a9010ab27f</Identifier>
<Accept>
<AcksTo>
<a:Address>http://localhost:8888/</a:Address>
</AcksTo>
</Accept>
</CreateSequenceResponse>
</s:Body>
</s:Envelope>

Now, because of the way each method is implemented (invoking

callback.Result(result) method at the end of each "primary"

operation), a response to a request received by an endpoint is returned over

the callback channel. This happens under-the-cover even though all messages

in the "primary" interface are defined as One-way operations.


The behavior is quite analogous to a Request-Response

operation primitive. I wonder what are the usecases of wsDualHttpBinding ?


Summary


Finally, I summarize the reasons that makes

wsDualHttpBinding a non-interoperable binding:




  1. The specifications of cdp:CompositeDuplex

    and ow:OneWay are not available and these elements will

    thus be ignored by the Metro WSDL importing tool.



  2. The operations from

    "callback" interface are mapped as

    Notification operation

    in the WSDL. This operation primitive is not supported by Metro.




  3. On the service endpoint,

    all the operations from "primary" and "callback" interface are mapped to

    a single wsdl:portType. On the client side, wsdl:portType

    is mapped to separate "primary" and "callback" interfaces. The Java-to-WSDL

    mapping defined by the JAX-WS specification allows one-to-one mapping

    between Java interface and wsdl:portType.



Technorati:

webservices

interoperability

wcf

metro

jax-ws

wsit

Join the discussion

Comments ( 9 )
  • Christian Weyer: Smells like service spirit Thursday, August 2, 2007
    [Trackback] There you have it - very insightful article by Arun.
  • Scott Seely Saturday, August 4, 2007
    [Trackback] Arun Gupta recently asked what the use cases are for WSDualHttpBinding over here. To save you some time,...
  • Chuck Rianhard Monday, August 6, 2007
    Thanks Arun for the explanation.
    Below I've included a couple of use cases dealing with the callback capability inherent in the wsDualHttpBinding which I sent you privately but wanted to share with your blog readers as well:
    1) One of my use cases deals with a job request that takes an unknown about of time to process a job (in the host) due to load or complexity. A service request is made by the client and a Boolean value is immediately returned on the job request being accepted or denied. If accepted the requestor (client) knows that at some point in the future its (the client's) callback method will be called with the results of the job request from the host (of course there is a watchdog timer just in case). I have this working great with wsDualHttp in a WCF to WCF environment currently and have a requirement to add a lightweight Java WSIT client.
    2) Another possible use case, that I have not yet done but plan on, deals with a publish/subscribe scenario where a client subscribes to receive certain events. The client would receive these events through its callback.
  • Mike Taulty's Blog Monday, August 6, 2007
    [Trackback] Interesting post&nbsp;(via Christian)
  • MSGuy Monday, January 28, 2008

    I guess we should all just start using Java instead. ;)


  • raj Sunday, September 21, 2008

    Could any one tell me whether WSHttpBinding is Interoparable with java?

    is there any example on how to do that.


  • Arun Gupta Sunday, September 21, 2008

    Raj,

    http://blogs.sun.com/arungupta/entry/glassfish_v2_beta3_and_vista is an example that shows how a WCF reliable endpoint is interoperable with Metro stack. A much more extensive set of test results (from Microsoft plugfest) are available at:

    http://weblogs.java.net/blog/haroldcarr/archive/2008/03/metro_web_servi_2.html


  • Harold Carr's Blog Thursday, April 9, 2009
    [Trackback] Clear back in August 2007 Arun Gupta wrote a blog entry with the
    title "wsHttpDualBinding - a non-interoperable binding". In point of
    fact, that binding is interoperable. My current entry explains the details.
  • David Monday, October 10, 2011

    The latest article on this topic is here:

    http://weblogs.java.net/blog/haroldcarr/archive/2009/04/metro_interoper.html

    This article isn't correct.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.