I’ve often written about how to write custom channels; transports in particular. In all of the examples I’ve given, the same transport is used for both sending and receiving messages (i.e. HTTP out, HTTP in). This parallelism fails in certain scenarios. For example, WS-Discovery defines a pattern where you send out a UDP Multicast probe (a broadcast request to find a peer), and expect (one or more) HTTP unicast responses back.
Constructing a binding for this scenario requires three pieces:
- An outgoing transport
- An incoming transport
- A correlation mechanism to tie the request to the response
For the transports, you need a BindingElement
that returns the outgoing transport from BuildChannelFactory
and the incoming transport from BuildChannelListener
. One way of doing this is with a CompositeTransportBindingElement. A CompositeTransportBindingElement uses two bindings to build its runtime components. For example, you can pass in a binding that consists of OneWayBindingElement + HttpTransportBindingElement. Or one that contains UdpBindingElement.
For correlation, if you add CompositeDuplexBindingElement
to the stack, you can configure a ClientBaseAddress and Service Model will provide correlation using WS-Addressing. You could also provide correlation yourself (which is actually a good topic for later this week :))
The relevant pieces of CompositeTransportBindingElement (posted here) are:
class
CompositeTransportBindingElement :
TransportBindingElement
{
Binding
channelBinding;
Binding
listenerBinding;
public
CompositeTransportBindingElement( Binding channelBinding, Binding listenerBinding) { this.channelBinding = channelBinding; this.listenerBinding = listenerBinding; }
public override
IChannelFactory<TChannel> BuildChannelFactory<TChannel>(
BindingContext
context) {
return
channelBinding.BuildChannelFactory<TChannel>( context.BindingParameters); }
public override
IChannelListener<TChannel> BuildChannelListener<TChannel>(
BindingContext
context) {
return
listenerBinding.BuildChannelListener<TChannel>( context.ListenUriBaseAddress, context.ListenUriRelativeAddress, context.ListenUriMode, context.BindingParameters); } }