As I implied in an earlier post, there’s a little more to the ServiceModel Channel Shapes then meets the eye. What I listed in the contract->shape mapping last week shows all the possibilities of what ServiceModel will request. However, it glosses over the process of how the channel requested is mapped to your service method. When you use ServiceModel, you get an extra layered channel at the top of your channel stack. The “Service Channel” has logic to normalize channel shapes into one-way and request reply patterns.
For example, let’s say you have method such as:
Since this operation isn’t marked “IsOneWay=true”, it requires a request-reply channel. If you have a channel stack that only offers IRequestChannel, then Service Channel will use that shape directly. If your stack doesn’t offer IRequestChannel, but can create IDuplexSessionChannel, then ServiceModel will layer IRequestChannel on top of IDuplexSessionChannel (similar to how HTTP request reply is layered on top of a TCP connection).
With all this adaptation going on, how can you figure out what your stack will look like from a shape perspective? It’s not easy, but fortunately most users don’t need to worry about these details, they can simply trust that ServiceModel is creating a stack compatible with their endpoint. To decipher the magic, you need to understand what shapes each layer can offer, and under which conditions. For transports, it’s relatively straightforward, as they offer up fairly constant shapes (though they do occasionally vary based on configuration parameters). For layered channels you need to understand the mapping between what the layer beneath offers up, and how your layered channel can build upon those choices. That’s a topic for another time. For now, here are the choices for the transports:
The most common mode for Http is IRequestChannel/IReplyChannel. In order to support 2-way sessions, we also define a one-way mapping for Http. You can request IOutputChannel/IInputChannel from our Http Transport. In one-way mode, we will return a “202 Accepted” response with an empty body immediately on receipt of the Http request. We send this response before we dispatch the received message so that we can emulate datagram to the best of our capabilities given the inherent request-response nature of Http. When using
WsDualHttpBinding you will see this behavior.
UPDATE (5/23/06, 9:22AM): In the latest V1 bits we’ve gotten crisper about our channel shapes. As Http is not natively one-way, it no longer supports IOutputChannel/IInputChannel. Rather, this “one-way over request-reply” functionality is provided by a layered binding element called
OneWayBindingElement. Details of how this mapping works are outlined here.
TCP and Named Pipes have the same capabilities and support two patterns: IRequestChannel/IReplyChannel, and IDuplexSessionChannel. IDuplexSessionChannel is the natural shape of a “connection” (socket/pipe) and is the shape we return by default. An IDuplexSessionChannel maps 1-1 to a connection. Fortunately IDuplexSessionChannel also offers the most flexibility to the layers above it. You can build any other pattern (IOuputChannel/IInputChannel, IRequestChannel/IReplyChannel, IOutputSessionChannel/IInputSessionChannel, and IRequestSessionChannel/IReplySessionChannel) on top of IDuplexSessionChannel. The one pragmatic restriction of IDuplexSessionChannel is that it does not support Message Streaming. If you have streaming enabled on your binding (TransferMode != TransferMode.Buffered), then we use the IRequestChannel/IReplyChannel shape. In streaming mode, we need to use connections in more of an HTTP-like manner. A connection is exclusively checked out for the lifetime of a request-reply pair, and returned to a connection pool when the request-reply pair has completed.
Msmq not only supports IOutputChannel/IInputChannel, but they also support one-way session (IOutputSessionChannel/IInputSessionChannel) through a method they call “session-gram”. The way it works is that the Msmq Transport buffers all messages being sent on a sessionful channel, and when the session is closed they pass the entire session in a single Msmq message. This demarkated message is then received by the other queue and parsed into multiple messages.
As you might expect, when in “integration mode”, Msmq Transport offers up IOutputChannel/IInputChannel only.