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(CallbackContract=typeof(ICalculatorCallback)]
(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 = OperationContext.Current.GetCallbackChannel<ICalculatorCallback>();
(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=â€wsProfileDualHttpBindingâ€/> (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:output wsa:Action="..." message="tns:ICalculator_Display_OutputCallbackMessage"/> (09) <wsdl:input wsa:Action="..." message="tns:ICalculator_Display_InputCallbackMessage"/> (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:inputinstead 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" /> (03) <EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"> (04) <Address>http://wsstar/duplex/service.svc</Address> (05) </EndpointReference> (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) ServiceSite site = new ServiceSite(CalculatorCallback);
(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>http://wsstar:8000/Temporary_Indigo_Addresses/...698064</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>
The particular header element to notice is <a:ReplyTo> that
sends a HTTP address to service endpoint and thus enabling callback. ServiceSite
extends from CommunicationObject, but unfortunately it is not a
hyperlink (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 generate
an 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">http://wsstar:8000/Temporary_Indigo_Addresses/...698064</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
- 1232 reads





