Indigo Duplex Bindings
In part
1 of the series, I gave a short tutorial on Indigo
bindings. In this entry, I'll describe Indigo Duplex bindings and related code
sample.
Indigo Duplex Binding enables bi-directional communication between a service
and client. The steps
in Indigo documentation
are scattered unless I look at the Duplex
Contract sample. In this entry I'm listing all the steps and tried
explaining my understanding at each step with certain questions I'm still trying
to answer.
In a single direction communication, 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 service can invoke on client is
called as "callback" interface. To enable bi-directional
communication, here is what I need to do on the service side:
- Link the "primary" and "callback" interface by setting
CallbackContract property in the "primary" interface to the type of
the "callback" interface. - Get the CallbackChannel from OperationContext
specifying the "callback" interface
Here is the service endpoint interface showing the linking using CallbackContract
in line (01):
(01) [ServiceContract<font COLOR="#e86f00">(CallbackContract=typeof(ICalculatorCallback)</font>]
(02) public interface ICalculator {
(03) [OperationContract]
(04) double add(double n1, double n2);
(05) }
(06)
(07) public interface ICalculatorCallback {
(08) [OperationContract]
(09) void display(string line);
(10) }
Line (02) to (05) is the "primary" interface and line (07) to (10)
is the "callback" interface. Here is the service endpoint
implementation:
(01) public class CalculatorService : ICalculator {
(02) CalculatorCallback callback = null;
(03) public CalculatorService() {
(04) callback = <font COLOR="#e86f00">OperationContext.Current.GetCallbackChannel<ICalculatorCallback>();</font>
(05) }
(06)
(07) public double add(double n1, double n2) {
(08) callback.display(“Adding “ + n1 + “ and “ + n2);
(09) return n1 + n2;
(10) }
(11) }Line (03) to (05) is the constructor and retrieves the callback channel,
passing the generic type ICalculatorCallback. Line
(08) invokes the "callback" interface. The "callback" interface
is implemented on the client side but the
programming model requires it to be defined on the server side explicitly. Here
is the
binding configuration file:
(01) <configuration>
(02) <system.serviceModel>
(03) <services>
(04) <service serviceType=â€Calculatorâ€>
(05) <endpoint
(06) address=â€â€
(07) contractType=â€ICalculatorâ€
(08) bindingType=â€<font color="#e86f00">wsProfileDualHttpBinding</font>â€/>
(09) </service>
(10) </services>
(11) </system.serviceModel>
(12) </configuration>
Line (08) shows the WsProfileDualHttpBinding is
used and that's what enables duplex binding on the service. Once the service is
deployed in IIS, here is an Indigo generated wsdl:portType:
(01) <portType>
(02) <wsdl:operation name="Add">
(03) <wsdl:input wsa:Action="..." message="tns:ICalculator_Add_InputMessage"/>
(04) <wsdl:output wsa:Action="..." message="tns:ICalculator_Add_OutputMessage"/>
(05) </wsdl:operation>
(06)
(07) <wsdl:operation name="Display">
(08) <wsdl:<font COLOR="#e86f00">output </font>wsa:Action="..." message="tns:ICalculator_Display<font COLOR="#e86f00">_OutputCallbackMessage</font>"/>
(09) <wsdl:<font COLOR="#e86f00">input </font>wsa:Action="..." message="tns:ICalculator_Display<font COLOR="#e86f00">_InputCallbackMessage</font>"/>
(10) </wsdl:operation>
(11) </portType>The methods on "callback" interface, Display in our case, are
described in WSDL 1.1 using the following patterns:
wsdl:operationon line (07) resembles WSDL 1.1 solicit-response
operation, i.e. the sequence iswsdl:outputandwsdl:input
instead ofwsdl:inputandwsdl:outputin the
conventional request-response
operation.- The input message, on line (08), is suffixed with _InputCallbackMessage
and output message, on line (09), with _OutputCallbackMessage.
wsdl:port within wsdl:service looks like:
(01) <wsdl:port name="WSProfileDualHttpBinding_ICalculator_port" binding="i0:WSProfileDualHttpBinding_ICalculator">
(02) <soap:address location="http://wsstar/duplex/service.svc" /> <font COLOR="#e76f00">
</font>(03) <font COLOR="#e76f00"> <EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">
</font>(04) <font COLOR="#e76f00"> <Address>http://wsstar/duplex/service.svc</Address>
</font>(05) <font COLOR="#e76f00"> </EndpointReference>
</font>(06) </wsdl:port>
Line (03) to (05) shows an EndpointReference
within wsdl:port as an extensibility element. Now,
lets take a look at the client code:
(01) public class CalculatorClient {
(02) static void Main() {
(03) <font COLOR="#e76f00">ServiceSite site = new ServiceSite(CalculatorCallback);
</font>(04) CalculatorProxy proxy = new CalculatorProxy(site, "CalculatorEndpoint");
(05) double result = proxy.add(10.00D, 20.00D);
(06) Console.writeLine("Result is: " + result);
(07) }
(08) }
(09)
(10) public class CalculatorCallback : ICalculatorCallback {
(11) public void Display(string line) {
(12) Console.writeLine(line);
(13) }
(14) }
Line (01) to (08) is the client class and line (10) to (14) is the
implementation of the "callback" interface defined on the service. Most of the client code is simple except ServiceSite class,
in line (03), which
seems to perform the magic of enabling the callback. ServiceSite is
initialized by passing a reference to the implementation of "callback"
interface and then it is passed to the proxy constructor. Service endpoint is
invoked, via proxy, on line (05). I could not find much
documentation on how ServiceSite enables duplex contract but here
is the console output on the client-side:
(01) Adding 10.00 and 20.00
(02) Result is: 30.00
So the request goes from client to the service endpoint, line (08) in service
endpoint implementation above is invoke that displays line (01) in the console,
response comes back to client and then line (02) from the client code, in line
(06), is displayed.
Here is the SOAP header of the request message from client to service
endpoint:
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</a:Action>
<a:ReplyTo>
<a:Address><font COLOR="#e76f00">http://wsstar:8000/Temporary_Indigo_Addresses/...698064</font><font></a:Address>
</a:ReplyTo>
<a:MessageID>uuid:1adf8d20-bad9-47a1-90aa-8510c3b0bfec;id=0</a:MessageID>
<a:To s:mustUnderstand="1">http://localhost/duplex/service.svc</a:To>
</s:Header></font>The particular header element to notice is
<a:ReplyTo> thatsends a HTTP address to service endpoint and thus enabling callback.
ServiceSiteextends from
CommunicationObject, but unfortunately it is not ahyperlink (how I miss Javadoc
style documentation) and I could not find any other related documentation so I
still need to understand the magic behind how this header is generated. So far
my understanding is that specifying
ServiceSite seems to generatean HTTP endpoint, hosted on IIS, on port 8000 in
the context root Temporary_Indigo_Addresses. Is
this supposed to work on a non-Windows platform ?
Anyway, here is the SOAP header of the response message from service to client endpoint:
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequenceResponse</a:Action>
<a:RelatesTo>uuid:1adf8d20-bad9-47a1-90aa-8510c3b0bfec;id=0</a:RelatesTo>
<a:To s:mustUnderstand="1"><font COLOR="#e76f00">http://wsstar:8000/Temporary_Indigo_Addresses/...698064</font></a:To>
<RedirectTo s:mustUnderstand="1" xmlns="http://schemas.xmlsoap.org/ws/2004/06/addressingex">
<a:EndpointReference>
<a:Address>http://wsstar/duplex/service.svc</a:Address>
<Via>http://wsstar:8000/Temporary_Indigo_Addresses/...26df92</Via>
</a:EndpointReference>
</RedirectTo>
</s:Header>
Note that the <a:To> header uses the <a:ReplyTo>
header from the SOAP request message and thus enabling callback.
- Login or register to post comments
- Printer-friendly version
- arungupta's blog
- 1340 reads





