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:
classCompositeTransportBindingElement :TransportBindingElement{BindingchannelBinding;BindinglistenerBinding;publicCompositeTransportBindingElement( Binding channelBinding, Binding listenerBinding) { this.channelBinding = channelBinding; this.listenerBinding = listenerBinding; }public overrideIChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContextcontext) {returnchannelBinding.BuildChannelFactory<TChannel>( context.BindingParameters); }public overrideIChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContextcontext) {returnlistenerBinding.BuildChannelListener<TChannel>( context.ListenUriBaseAddress, context.ListenUriRelativeAddress, context.ListenUriMode, context.BindingParameters); } }