In Chapter 1, Jon introduces the concepts fundamental to using REST to build services. WCF in .NET 3.5 includes a sophisticated built-in mechanism that allows .NET developers to build RESTful services using the WCF programming model. In this excerpt, Jon shows how this works.
Isn't WCF All About SOAP?
You might be thinking, "Isn't WCF all about SOAP?" While you will probably find many people who think WCF is only used for building SOAP-based services (and many who think WCF is only for building RPC-styled SOAP-based services), it turns out that WCF is much broader than either of those communication styles. WCF is really a highly extensible framework with a common programming model and a totally pluggable communication infrastructure.
To illustrate the high-level extensibility of WCF, let's look at some technical details on particular pieces of WCF's plumbing. Although most of the time you won't be working at this low level, looking at this code will help your understanding of REST and WCF.
Channels and Dispatching
So what does WCF do, from a server-side perspective? The basic job of the WCF runtime is to listen for (or retrieve) messages from a network location, process those messages, and pass them to your code so that your code can implement the functionality of a service (Figure 2-1).
WCF's client-side programming model is symmetrical to that on the server side, but the processing of messages is in the opposite direction. Chapter 10 discusses the WCF programming model from the client perspective.
The transport channel
When you open a WCF server-side endpoint, WCF uses a channel listener to create a network listener called the transport channel to accept network traffic or use a network protocol to retrieve messages. When WCF is accepting messages (for example, when listening on a socket), it is acting as a passive listener. When WCF is looking for messages (for example, when using the MSMQ—Microsoft Message Queuing—protocol to connect to a named queue to retrieve messages), it is acting as an active listener. Regardless of listening style, the job of listening for messages is performed by what WCF refers to as a transport channel. Common transport channels include HTTP and MSMQ. In the case of the server side, the transport channel is created by a channel listener. The channel listener is a factory pattern object that is responsible for setting up the server-side listening infrastructure.
The message encoder
Next is the message encoder, which takes a network message and wraps it in an object that the rest of the WCF infrastructure can understand. This object is an instance of
Messageis modeled somewhat after a SOAP message pattern, with a header and a body, it isn't necessarily tied to the SOAP protocol.
Messageobject can be used to deserialize a message into a .NET object or retrieve it as XML (even if the underlying message is not formatted as XML). One important property of
Version. When this property is set to
MessageVersion.None, the object will ignore the
Headersproperty (in fact, an exception is raised if the
Headersproperty is used when
Versionis set to
Another interesting property is
Properties. This is a collection that can contain arbitrary objects, so it acts like a per-instance state bag. Interesting data can be placed into this collection, and other components up and down the stack can then communicate information indirectly through data on the message itself.
Optional objects follow the message encoder. WCF refers to these objects as channels, and to disambiguate them from transport channels, they are called protocol channels. Protocol channels implement protocols that might be useful for a particular service, such as security or reliable-messaging protocols. These objects are optional, but in certain services may be helpful or even required to implement a particular style of architecture.
The dispatching layer is responsible for invoking the proper methods on incoming message objects. First, the
IDispatchOperationSelectorobject determines which method is appropriate. Next, a pluggable component implements
IDispatchMessageFormatterto deserialize the
Messageobject into the proper .NET type. Finally, the
IOperationInvokerobject actually invokes the service.
Together, the transport channel, message encoder, protocol channels, and dispatcher are called the channel stack. WCF uses bindings to create the stack. A binding is really a piece of configuration, although it can be represented in memory as an object or serialized into an application configuration file. Based on the configuration of your service, through both attributes and another type of configuration called a behavior, WCF constructs the dispatching layer.
The infrastructure that creates the channel stack is not reliant on any particular programming model or communication mechanism. In other words, WCF is a pluggable pipeline-like architecture for creating channels of communication.
Using this programming model, WCF supports a wide variety of communication mechanisms. Suppose, for example, that you want the implementation to listen for SOAP-formatted messages over HTTP at a particular URI and then route those messages based on the SOAP action header's name. To do this, you can use either the
BasicHttpBinding objects, which derive from the binding base class and provide SOAP-based communication over HTTP.
If you use the default dispatch layer configuration, the
IDispatchOperationSelector looks at the incoming Message object for the SOAP action header and then uses .NET metadata to match the action header value to the name of a .NET method (this could be an exact match or could be customized using the
OperationContractAttribute). The dispatch layer then uses this information to deserialize the message into the accepted .NET types, and the
IOperationInvoker actually invokes the correct object.
The name of the default implementation is OperationSelector, which might indicate that there is only one, but this is actually just one potential implementation.
Although many of the WCF defaults in the dispatch layer lean toward a SOAP model, the channel stack has no real notion of anything "SOAP-y" in the least. It's only some of the WS-* protocols and WCF out-of-the-box (OOTB) bindings and objects that are aware of the SOAP protocol.
Given my assertion that WCF isn't tied to SOAP, what would it take to create a RESTful-based service using WCF? Not a whole lot, actually, since WCF has an HTTP listener (in the form of the HTTP transport channel), which isn't tied to
POST (i.e., it can handle other HTTP verbs). It also has a message encoder that understands XML messages, even when those messages aren't based on SOAP. Putting both of those pieces together gives us the basic building blocks for doing RESTful services with WCF.
You might be wondering about other incoming HTTP message body formats like form or JSON-encoded bodies—we'll deal with those in later chapters.