Friday, January 19, 2007 11:35 PM
jsmith
The Learning Channels...
The following is a rapid-fire description of channels, where they come from, and a code sample to illustrate:
Channels are one of the more complex parts of a WCF application. For those that are new to WCF, a channel is a sink or a source of a message, and they are largely hidden from the purview of the application developer. In fact, it is entirely possible (and common) to write a fully functional WCF application and not know a thing about channels. Even though they are not easily visible at the ServiceModel layer, they are busy behind the scenes sending, receiving, or otherwise mangling messages.
All channels are not created equal. In the WCF type system, there are channels for each supported transport, security functionality, and messaging protocol. Furthermore, a channel has at least one shape. For a description of channel shapes, see Kenny Wolf's blog. Since messaging applications frequently need to send messages securely over a given transport with a given protocol or choreography, channels can be stacked. Each channel in the stack is responsible for a specific set of functionality in the application.
User code never directly instantiates a channel; that job is reserved for special factory objects in the WCF type system. These factory objects come in two flavors: Channel Listeners and Channel Factories. Channel listeners create receiving channels, and channel factories create sending channels. Channel listeners have the added pleasure of listening for incoming connections (think sockets). A given channel factory or channel listener can create more than one kind of channel, but they are typically grouped based on functionailty. For example, the WCF type system contains a channel listener for TCP/IP traffic, and another one for MSMQ traffic. Since channels reside in a stack, and channel listeners/factories create channels, channel listeners/factories are also stacked at runtime.
User code never directly instantiates a channel listener or channel factory; that job is reserved for a BindingElement. The WCF API contains several BindingElements, and each one represents some messaging functionality (e.g. transport, messaging protocols, security, transactional support, encoding). All BindingElements have a common base type, and that base type defines methods called BuildChannelFactory and BuildChannelListener. As their name implies, these methods build at least one channel factory or channel listener, respectively. Application code can instantiate and use BindingElement to build a single channel listener or channel factory. It is a one-stop shop for both the sender and the receiver.
In practice, however, BindingElements are most frequently created by a Binding. A Binding’s primary job is to create a collection of BindingElements, and use that collection of BindingElements to build either a stack of channel factories or a stack of channel listeners. All Bindings have a common base type, and that base type defines a method named CreateBindingElements. At runtime, either the sending application or the receiving application calls this method, and then uses the returned BindingElementCollection to create a stack of channel listeners or channel factories.
Channel listeners, channel factories, and channels all have a common state machine. Since these objects are typically arranged in a stack, the entire stack must transition through the state machine in harmony.
To summarize:
- Binding begat a BindingElementCollection
- BindingElementCollection begat a stack of channel listeners or channel factories
- RECEIVER: stack of channel listeners begat a stack of channels
- SENDER: stack of channel factories begat a stack of channels
Trying to keep this straight can be challenging at first. If you add the state transitions, and the fact that a channel listener or factory stack can create multiple channel stacks, it can be quite confusing at first. In the end, however, this model provides tremendous extensibility and functionality, so I think it is a good one.
One great way to learn channels and the impact ServiceModel code has on them is to write a custom channel, plug it into a running application, and watch what is going on. The following code sample does just that: DelegatorChannelDemo1.zip (140.11 KB)
The zip file contains two projects: TestApp and DelegatorChannel. DelegatorChannel project contains a channel factory, a channel listener, a BindingElement, and a Binding that will place a custom channel in the channel stack at runtime. These channels simply dump text to the console for all state changes, as well as all method calls. The channel factory and channel listener do the same. The Binding in the DelegatorChannel project inserts a custom BindingElement in the BindingElementCollection for the BasicHttpBinding, NetTcpBinding, WsHttpBinding, and NetMsmqBinding. The TestApp project flexes this binding in several different MEPS (Datagram, Request/Reply, and Duplex).
BTW - My book should be on the bookshelves by TechEd (yay).