Channels can perform a variety of functions. Virtually any type of messaging functionality can be written into a channel and plugged into the WCF runtime. We can, however, broadly categorize the types of tasks that a channel can perform. At the conceptual level, a channel can facilitate the use of a particular transport, messaging protocol, or channel shape.
Transport channels are channels that interact with the network, file system, memory, or other application (like Microsoft SQL Server 2005, SAP, or Oracle). Each transport supported by WCF out of the box has at least one matching WCF transport channel. For example, WCF supports TCP/IP communication, and the means by which a WCF application interacts with sockets is a TCP/IP channel. Other supported transports are HTTP, Named Pipes, and MSMQ, and each of these transports has at least one transport channel associated with it.
While TCP/IP, HTTP, Named Pipes, and MSMQ represent the mainstream transports in use today, applications might require additional transports. Although the possibilities abound, some candidates are file system, Simple Mail Transfer Protocol (SMTP), Post Office Protocol 3 (POP3), and File Transfer Protocol (FTP). If one thinks a little outside the box, it is not too hard to conceive of other transports as well. Consider the SQL Server 2005 Service Broker. Although this is not a standard transport, treating it as such by creating a WCF transport channel provides WCF applications access to its features through the standard WCF programming model. With a Service Broker custom channel in place, application developers could leverage the Service Broker just as easily as they could leverage WS-* over HTTP. In effect, this type of custom transport channel allows the application developer to focus more on the business functionality of the application rather than the Service Broker access points or API. The same concept beneath writing a custom transport channel for the SQL Server 2005 Service Broker also applies to other enterprise computing applications like SAP and Oracle.
Transport channels are always the bottommost channel in a channel stack. From the sender’s perspective, a transport channel is the last channel in the stack to interact with the data before it is sent to the chosen transport. From the receiver’s perspective, a transport channel is the first channel in the stack to interact with the data before it is sent to other channels in the stack. In effect, other channels in the channel stack do not need to know the transport used in the application. A channel stack without a transport channel is of little or no value (except perhaps for a philosophical debate)–all channel stacks must contain at least one transport channel. As you’ll see in the section “Shaping Channels” later in this chapter, some channel stacks can even contain more than one transport channel.
Protocol channels are the means by which WCF implements messaging protocols like WS-ReliableMessaging, WS-AtomicTransaction, and WS-SecureConversation. In fact, all WS-* specifications supported by WCF are implemented as protocol channels. Since WS-* specifications frequently dictate that one application-level message exchange can actually generate more than one message at the transport layer, WS-* protocol channels frequently generate messages that are not surfaced to any higher channel in the channel stack. For example, consider the channel stack shown in Figure 6-3.
Figure 6-3: Channel stack with a WS-ReliableMessaging protocol channel
When the sending application passes a Message to the channel stack, the channel stack will ultimately encode the Message and send the bytes over the wire. Because there is a WS-RM channel in the channel stack, however, more than one Message is encoded and sent over the wire. In effect, the WS-RM channel can generate its own Message objects and send them to the next channel in the channel stack. Because WS-RM requires reply messages, the channels below the WS-RM channel must also be able to accept WS-RM reply messages. The WS-RM reply messages are pulled up the channel stack until they reach the WS-RM channel. Upon receipt of a WS-RM reply message, the WS-RM channel can then take some action as prescribed by the WS-RM specification, and the WS-RM channel is not required to pass that information to channels higher in the channel stack. If the sending application is using a two-way contract, the WS-RM channel will eventually pass a Message on to higher channels in the channel stack. More than one protocol channel can exist in a channel stack. In Figure 6-3, four protocol channels are shown. Each of these protocol channels functions in a manner similar to the aforementioned WS-RM example.
Shaping channels allow a channel stack to change shape within the channel stack. In so doing, shaping channels create a means for leveraging existing building blocks in new ways. For example, MSMQ is a means to send one-way messages to another application, and WCF supports the use of MSMQ in this manner. A custom shaping channel allows a WCF application to use MSMQ for duplex communication. Because duplex communication is at the atomic level a matter of sending and receiving messages concurrently, an MSMQ duplex shaping channel would need to wrap an MSMQ receiving channel and an MSMQ sending channel, as shown in Figure 6-4.
Figure 6-4: A shaping channel
Figure 6-4 shows that the shaping channel wraps an IInputChannel and an IOutputChannel to provide an IDuplexChannel shape to channels above it (hence the name). In practice, a shaping channel is not a trivial channel to write, as they can present interesting threading and synchronization concerns. As an example, consider the channel state machine transitions for a shaping channel. Since a shaping channel wraps other channels, all of the wrapped channels must transition through the channel state machine with the shaping channel. Because the channel above the shaping channel can invoke the BeginOpen and BeginClose methods on the shaping channel, the shaping channel must return an IAsyncResult that represents the IAsyncResult objects returned from the BeginOpen and BeginClose methods on the subordinate channels. For more information on this topic in particular, I recommend downloading and reviewing the PowerThreading library available at http://wintellect.com, as well as reviewing the threading chapter in Jeffrey Richter’s CLR via C#.