Export (0) Print
Expand All
3 out of 4 rated this helpful - Rate this topic

WCF RESTful Programming Model

This chapter is excerpted from RESTful .NET: Build and Consume RESTful Web Services with .NET 3.5 by Jon Flanders, published by O'Reilly Media

In Chapter 1, REST Basics, I introduced the concepts fundamental to using REST to build services. WCF in .NET 3.5 includes a sophisticated built-in mechanism that allows you, a .NET developer, to build RESTful services using the WCF programming model.

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.

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, "The WCF server-side stack").

Note
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, Consuming RESTful XML Services Using WCF discusses the WCF programming model from the client perspective.

Figure 2.1. The WCF server-side stack

The WCF server-side stack
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 System.ServiceModel.Channels.Message. Although Message is modeled somewhat after a SOAP message pattern, with a header and a body, it isn't necessarily tied to the SOAP protocol.

The Message object 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 Message is Version. When this property is set to MessageVersion.None, the object will ignore the Headers property (in fact, an exception is raised if the Headers property is used when Version is set to MessageVersion.None).

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.

Protocol channels

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 dispatcher

The dispatching layer is responsible for invoking the proper methods on incoming message objects. First, the IDispatchOperationSelector object determines which method is appropriate. Next, a pluggable component implements IDispatchMessageFormatter to deserialize the Message object into the proper .NET type. Finally, the IOperationInvoker object 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 WsHttpBinding or 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.

Note
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.

Note
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.

It turns out that the facility to use REST existed in WCF even before .NET 3.5. (For clarity, I'll refer to the version that shipped with .NET 3.0 as WCF 3.0, and the version that ships with .NET 3.5 as WCF 3.5.) WCF 3.0 actually has the infrastructure for doing RESTful-style programming, but it lacks any sort of standard RESTful programming model. Most of the remainder of this book will focus on the WCF programming model rather than on the communication infrastructure. In this section we'll spend some time on the communication layer to illustrate a few key points. First, WCF isn't tied to SOAP, even in WCF 3.0. Second, the communication infrastructure of WCF was written well enough to support different communication styles without modification in WCF 3.5. WCF 3.5 adds a programming model for REST that we could build without Microsoft's help if we were so inclined.

It is possible to use WCF 3.0 to put together an HTTP endpoint that doesn't use SOAP. To do this, we first require a binding to create the correct channel stack. However, WCF 3.0 doesn't include any OOTB bindings that fit the bill (they all default to using SOAP), so we will have to create a custom binding using a CustomBinding object and adding the correct BindingElements. These BindingElements will be used to build the channels in the channel stack.

Note
We could also build a class that derives from the binding base class, which would be the right thing to do if we were going to reuse this binding in more than one project.

For this binding we will need, at minimum, a message encoder and a transport channel. These two objects are the only required elements for a channel stack. For most RESTful services, that's all we'll ever need in the channel stack-there are very few situations in which we would want to use other protocol channels. The BindingElements have to be added to the binding in the reverse order that they will be used, so we add the TextMessageEncodingBindingElement first, followed by HttpTransportBindingElement (which specifies the use of the HTTP transport in the channel stack). Example 2.1, "Creating a custom binding" shows the code that creates the custom binding (as always, this could instead be part of a configuration file).

Example 2.1. Creating a custom binding

CustomBinding b = new CustomBinding();
TextMessageEncodingBindingElement msgEncoder;
msgEncoder = new TextMessageEncodingBindingElement();
msgEncoder.MessageVersion = MessageVersion.None;
b.Elements.Add(msgEncoder);
HttpTransportBindingElement http;
http = new HttpTransportBindingElement();
b.Elements.Add(http);

Note that this code changes the MessageVersion property to MessageVersion.None. This instructs the TextMessageEncoder not to look for anything "SOAP-y," although it still will only process incoming messages that are formatted as XML (since this is what the TextMessageEncoder is programmed to do).

Next, we must construct an endpoint. A WCF endpoint has three parts: an address, a binding, and a contract. The binding dictates the look of the channel stack and determines how the endpoint will communicate. The address is the URI at which the endpoint will listen, and the contract contains information about the type that WCF will use to route messages. In WCF, the contract will be a .NET type with the ServiceContractAttribute, and this type can be either an interface or a .NET class. In this case I am specifying a .NET class as the contract.

The next step is to host the endpoint so that WCF will create a channel listener to start the channel stack. In most cases, the class named ServiceHost will carry out this part (see Chapter 5, Hosting WCF RESTful Services for more information about hosting WCF endpoints).

After creating the ServiceHost instance, add a ServiceEndpoint using the CustomBinding, an HTTP-based URI as the address, and a type named SimpleHTTPService as the contract. This code also uses Console.ReadLine as the mechanism to keep the process alive while requests are being processed. We can create a console application to host my WCF endpoint. Example 2.2, "SimpleHTTPService using WCF" shows the Main method from my console application.

Example 2.2. SimpleHTTPService using WCF

static void Main(string[] args)
{
CustomBinding b = new CustomBinding();
TextMessageEncodingBindingElement msgEncoder;
msgEncoder = new TextMessageEncodingBindingElement();
msgEncoder.MessageVersion = MessageVersion.None;
b.Elements.Add(msgEncoder);
HttpTransportBindingElement http;
http = new HttpTransportBindingElement();
b.Elements.Add(http);
ServiceHost sh = new ServiceHost(typeof(SimpleHTTPService));
ServiceEndpoint se = null;
se = sh.AddServiceEndpoint(typeof(SimpleHTTPService),
    b,
    "http://localhost:8889/TestHttp");
sh.Open();
Console.WriteLine("Simple HTTP Service Listening");
Console.WriteLine("Press enter to stop service");
Console.ReadLine();
}

This code may lead you to wonder what SimpleHTTPService looks like. SimpleHTTPService is a class that includes one method (this is typically referred to in WCF terminology as a universal operation). Instead of having regular .NET types as input and output parameters to the method, we are using System.ServiceModel.Channels.Message.

Using Message means that the WCF dispatch layer doesn't have to deserialize the incoming message into specific .NET types. Adding the OperationContractAttribute and setting its Action property equal to * and the ReplyAction property equal to * indicates that all messages, regardless of action, will be routed to this method. Admittedly, having to use SOAP header information is kind of non-RESTful, since we are annotating the class with SOAP-based attributes, but the values of these properties actually short-circuit any SOAP-based routing. Example 2.3, "SimpleHTTPService implementation" shows the code for the SimpleHTTPService.

Example 2.3. SimpleHTTPService implementation

[ServiceContract]
public class SimpleHTTPService
{
[OperationContract(Action = "*", ReplyAction = "*")]
Message AllURIs(Message msg)
{
    HttpRequestMessageProperty httpProps;
    string propName;
    propName = HttpRequestMessageProperty.Name;
    httpProps = msg.Properties[propName] as HttpRequestMessageProperty;
    string uri;
    uri = msg.Headers.To.AbsolutePath;
    Console.WriteLine("Request to {0}", uri);
    if (httpProps.Method != "GET")
    {
        Console.WriteLine("Incoming Message {0} with method of {1}",
            msg.GetReaderAtBodyContents().ReadOuterXml(),
            httpProps.Method);
    }
    else
    {
        Console.WriteLine("GET Request - no message Body");
    }
    //print the query string if any
    if (httpProps.QueryString != null)
        Console.WriteLine("QueryString = {0}", httpProps.QueryString);
    Message response = Message.CreateMessage(
        MessageVersion.None,
        "*",
        "Simple response string");
    HttpResponseMessageProperty responseProp;
    responseProp = new HttpResponseMessageProperty();
    responseProp.Headers.Add("CustomHeader", "Value");
    return response;
}

Figure 2.2, "Testing WCF 3.0 HTTP service" shows the results of testing the client (which is just a browser in this case) and the output from the service in the console application.

Figure 2.2. Testing WCF 3.0 HTTP service

Testing WCF 3.0 HTTP service

Due to the structure of WCF 3.0, the endpoint created here will route all incoming network requests to the single method. While it would be possible to use .NET 3.0 to automatically dispatch different network messages to different methods without using SOAP (since the default dispatching is based on the concept of Action), it requires adding a fair amount of custom code into the WCF channel stack and dispatching layer. This is one of the things included in WCF 3.5, which we'll examine in a moment.

There is something else to note about the code in the body of the AllURIs method in the earlier code sample. Notice how I am asking the Message object for a property from its Properties collection. The property is an instance of the HttpRequestMessageProperty type, which is a property populated by the HTTP transport channel. As you can see from the code, this property has all the information about the current HTTP request, including the Method and the incoming HTTP headers. Message properties are indexed by name, so the static Name property of the HttpReque⁠s⁠tM⁠e⁠s⁠s⁠a⁠g⁠e⁠Property is used to find the property inside of the Message (of course my code is assuming the binding being used has the HTTP transport channel in use and that the property will always be there). If I wasn't using Message as the parameter type I could access the property via the OperationContext.Current.IncomingMessageProperties collection. Example 2.4, "HttpRequestMessageProperty definition" is the full definition of the HttpRequestMessageProperty.

Example 2.4. HttpRequestMessageProperty definition

namespace System.ServiceModel.Channels
{
    public sealed class HttpRequestMessageProperty
    {

        public WebHeaderCollection Headers { get; }
        public string Method { get; set; }
        public static string Name { get; }
        public string QueryString { get; set; }
        public bool SuppressEntityBody { get; set; }
    }
}

The code at the end of the AllURIs method in Example 2.2, "SimpleHTTPService using WCF" creates an HttpResponseMessageProperty object, which is the corollary object to the HttpRequestMessageProperty object. The HTTP transport channel will use this property to set parts of the HTTP response. The code creates and sets the value of a custom HTTP header. Example 2.5, "HttpResponseMessageProperty definition" includes the full definition of the HttpResponseMessageProperty.

Example 2.5. HttpResponseMessageProperty definition

namespace System.ServiceModel.Channels
{
    public sealed class HttpResponseMessageProperty
    {
        public static string Name { get; }
        public HttpStatusCode StatusCode { get; set; }
        public string StatusDescription { get; set; }
        public bool SuppressEntityBody { get; set; }
    }
}

HttpWebRequestMessageProperty and HttpWebResponseMessageProperty are important tools when using WCF for HTTP, and since RESTful services use HTTP, we'll find them helpful there as well. You'll see these properties being used throughout this book to enhance our RESTful services.

So, what insight into WCF does the code in Examples 2.1 and 2.2 provide? Mainly, that WCF is not just about SOAP, and that WCF has included most of the facilities to support RESTful services since the beginning. What was lacking in 3.0 was an explicit programming model for REST.

With the introduction of WCF 3.5, the WCF channel stack and dispatching layer look like the drawing in Figure 2.3, "The WCF 3.5 server-side stack".

Figure 2.3. The WCF 3.5 server-side stack

The WCF 3.5 server-side stack

The WCF 3.5 web programming model provides features that build on the 3.0 model to make RESTful programming possible with WCF without adding a significant amount of custom code. These are contained in the System.ServiceModel.Web.dll assembly, which is new for WCF 3.5. Here is a list of the features that make it easier to build RESTful services:

WebHttpBinding

An OOTB binding that uses the HTTP transport and text message encoder (with its MessageVersion set to None). This is something that could be done in 3.0 with a CustomBinding, as shown in the previous section. Having an OOTB binding is definitely a timesaver.

WebBehavior

This is an endpoint behavior that will modify the dispatch layer on all operations on a contract. The modifications cause messages to be dispatched to methods on your service based on URIs and HTTP verbs (rather than the default, which is to dispatch based on the SOAP action header).

WebServiceHost

This is a ServiceHost-derived class that simplifies the configuration of a web-based service. Also included is a WebServiceHostFactory for IIS/WAS hosting scenarios (hosting is discussed in more detail in Chapter 5, Hosting WCF RESTful Services).

WebOperationContext

This is a new context object, which contains the state of the incoming request and outgoing response, and simplifies coding against HTTP using WCF.

WebGetAttribute and WebInvokeAttribute

Two new operation behaviors that are applied as attributes on a ServiceContract's methods that already are operations because they have the OperationContractAttribute applied. On each method, using these attributes declares which part of the uniform interface (GET, POST, PUT, and DELETE) the CLR method should implement. WebGetAttribute is for GET and WebInvokeAttribute is for all the other parts of the uniform interface. It also tells the dispatcher how to match the methods to URIs, and also how to parse the URI into method parameters.

You can see this set of objects applied in Figure 2.3, "The WCF 3.5 server-side stack". The code shown in my next example reimplements the WCF 3.0 HTTP-based service from Example 2.2, "SimpleHTTPService using WCF" using WCF 3.5. Example 2.6, "WCF 3.5 version of Main" shows the Main method of the Console Application host, after adding a reference to System.ServiceModel.Web.dll and adding a using statement to the code file for System.ServiceModel.Web.

Example 2.6. WCF 3.5 version of Main

static void Main(string[] args)
{
    WebHttpBinding binding;
    binding = new WebHttpBinding();
    WebServiceHost sh;
    sh = new WebServiceHost(typeof(SimpleHTTPService));
    sh.AddServiceEndpoint(typeof(SimpleHTTPService),
        binding,
        "http://localhost:8889/TestHttp");
    sh.Open();
    Console.WriteLine("Simple HTTP Service Listening");
    Console.WriteLine("Press enter to stop service");
    Console.ReadLine();

}

This code contains considerably fewer lines than the WCF 3.0 version shown in Example 2.2, "SimpleHTTPService using WCF". Instead of having to create a CustomBinding, this code uses the WebHttpBinding, which uses the HTTP transport, as well as a text encoder with its MessageVersion set to MessageVersion.None.

This code also uses the new WebServiceHost class. The WebServiceHost API is exactly the same as the standard ServiceHost class based on how you program against it, as it still requires AddServiceEndpoint (or the configuration file) for all the endpoints it will host. But when the code calls WebServiceHost.Open, some behind-the-scenes magic happens (well not really magic, but stuff happens automatically). WebServiceHost overrides the ServiceHostBase.OnOpening method, loops through all the endpoints, and adds a special new behavior to each endpoint. This behavior, named WebHttpBehavior, modifies the WCF dispatching layer to route messages to methods on your service based solely on the URI. It adds the WebHttpBehavior to all endpoints of the service, so use WebServiceHost only when hosting RESTful endpoints. If the service contains any non-RESTful endpoints, use ServiceHost and add the WebHttpBehavior manually to only the endpoints that require it.

Example 2.7, "WCF 3.5 SimpleHTTPService implementation" shows the WCF 3.5 version of my service.

Example 2.7. WCF 3.5 SimpleHTTPService implementation

[ServiceContract]
public class SimpleHTTPService
{

    [OperationContract()]
    [WebGet(UriTemplate="*")]
    Message AllURIs(Message msg)
    {
        WebOperationContext webCtx;
        webCtx = WebOperationContext.Current;
        IncomingWebRequestContext incomingCtx;
        incomingCtx = webCtx.IncomingRequest;
        string uri;
        uri = incomingCtx.UriTemplateMatch.RequestUri.ToString();
        Console.WriteLine("Request to {0}", uri);
        if (incomingCtx.Method != "GET")
        {
            Console.WriteLine("Incoming Message {0} with method of {1}",
                msg.GetReaderAtBodyContents().ReadOuterXml(),
                incomingCtx.Method);
        }
        else
        {
            Console.WriteLine("GET Request - no message Body");
        }
        NameValueCollection query;
        query = incomingCtx.UriTemplateMatch.QueryParameters;
        //print the query string if any
        string queryName;
        if (query.Count != 0)
        {
            Console.WriteLine("QueryString:");
           var enumQ = query.GetEnumerator();
           while(enumQ.MoveNext())
           {
               queryName = enumQ.Current.ToString();
               Console.WriteLine("{0} = {1}", queryName, query[queryName]);
           }
        }
        Message response = Message.CreateMessage(
            MessageVersion.None,
            "*",
            "Simple response string");
        OutgoingWebResponseContext outCtx;
        outCtx = webCtx.OutgoingResponse;
        outCtx.Headers.Add("CustomHeader", "Value");
        return response;
    }
}

One big difference between the 3.0 and 3.5 versions of this code is that the OperationContractAttribute on the CLR method doesn't have to use * as the values for the Action and ReplyAction properties, since the new dispatch layer doesn't Action for routing at all. In the 3.5 version, the dispatching is based on the URIs and the HTTP verbs rather than the SOAP action header value. WCF will ignore all of the SOAP-specific properties when WebHttpBinding is used.

WebHttpBinding

The WebHttpBinding class is a new OOTB binding in WCF 3.5, designed to be the binding for RESTful WCF endpoints.

The binding is pretty simple, and is very much like the CustomBinding used in my WCF 3.0 example earlier in the chapter (Example 2.1, "Creating a custom binding"). WebHttpBinding contains a binding element that creates the HTTP (or HTTPS) WCF transport channel to listen for or send messages over HTTP(S). It also contains a message-encoder binding element that sets the channel stack's encoder to TextMessageEncoder, with the Version set to MessageVersion.None (no SOAP expected).

In some cases, you may still have to create a CustomBinding, but the WebHttpBinding type will suffice the majority of the time.

WebHttpBehavior

WebHttpBehavior is one of the key pieces of the WCF 3.5 programming model. The job of the WebHttpBehavior is to modify the WCF dispatching layer to use RESTful-based context to route messages to the CLR methods of the service object, and to modify the serialization layer to use the correct objects to deserialize requests and serialize responses.

Although the WebHttpBehavior itself can't be customized, it is influenced by other settings, mostly the new attributes for OperationContractAttribute methods, which I'll discuss in a moment.

The code shown in Example 2.3, "SimpleHTTPService implementation" does not explicitly use the WebHttpBehavior type; rather, the WebServiceHost added it automatically.

WebServiceHost

WebServiceHost is a new class in WCF 3.5 that derives from the ServiceHost class. Recall that ServiceHost is the piece of the WCF infrastructure that starts channel listeners for each endpoint.

WebServiceHost is similar in functionality to ServiceHost, but it simplifies the configuration of its endpoints by assuming the WebHttpBinding and automatically applying the WebHttpBehavior to all the endpoints. WebServiceHost can also auto-configure endpoints in cases where the service type (the type that is passed to its constructor) only has one contract. Chapter 5, Hosting WCF RESTful Services goes into much more detail on WebServiceHost.

WebOperationContext

In terms of programming against the HTTP API in WCF, the implementation of the AllURIs method remains fairly unchanged between the WCF 3.0 and WCF 3.5 versions. However, in WCF 3.5, you can use the WebOperationContext object inside the method body to interrogate the incoming request, instead of having to rely on information from both OperationContext and the HTTP message properties (HttpRequestMessageProperty and HttpResponseMessageProperty). WebOperationContext attaches itself to the OperationContext using IExtension<OperationContext>. IExtension of t is used to attach one object to another as an extension.

As an extension of OperationContext, WebOperationContext wraps the HttpRequestMessageProperty and HttpResponseMessageProperty with other, more explicitly typed properties that simplify programming against commonly used HTTP constructs. Chapter 11, Working with HTTP includes more information about programming against these constructs.

WebOperationContext has four properties, each of which represents a different part of an HTTP request/response message exchange sequence. Example 2.8, "WebOperationContext definition" is the full definition of WebOperationContext.

Example 2.8. WebOperationContext definition

namespace System.ServiceModel.Web
{
    public class WebOperationContext : IExtension<OperationContext>
    {
        public static WebOperationContext Current { get; }
        public IncomingWebRequestContext IncomingRequest { get; }
        public IncomingWebResponseContext IncomingResponse { get; }
        public OutgoingWebRequestContext OutgoingRequest { get; }
        public OutgoingWebResponseContext OutgoingResponse { get; }

    }
}

The static Current property will retrieve the correct WebOperationContext instance for the currently executing request. The remaining properties represent the four potential call points in an incoming or outgoing HTTP request. IncomingRequest and OutgoingResponse are server-side properties for introspecting and modifying HTTP properties. OutgoingRequest or IncomingResponse are responsible for setting the properties on the HTTP request or looking at the HTTP response on the client side. See Chapter 11, Working with HTTP for more information about these important context objects.

Another simplification provided by WCF 3.5 is that WebOperationContext parses the QueryString. While you can view this data in WCF 3.0 using the OperationContext, you must write the code to parse those parameters. In WCF 3.5, you can use the QueryParameters collection on the IncomingRequest property to view the data in a more easily readable format. Additionally, you can use the OutgoingResponse property to set a custom HTTP header on the response, instead of having to create and set the HttpResponseMessageProperty.

WebGetAttribute

Also note that I added a new attribute to the method on the service in Example 2.7, "WCF 3.5 SimpleHTTPService implementation": WebGetAttribute. The new dispatch layer will use this attribute to determine which method to call for a particular incoming request.

If you don't customize WebGetAttribute, the URI of the service (since there is only one method at this point) will be http://localhost:8889/TestHttp/AllURIs. By default, WCF 3.5 uses the CLR method name as part of the URI. This is true for both WebGetAttribute and WebInvokeAttribute.

If you want the resource URI model of your RESTful service to follow the constraints and guidelines of REST, you should customize the URI. If you use the default URIs, you can end up with two URIs for a single resource if you want to use more than one verb from the uniform interface. Having two URIs for a single resource would violate one of the most important constraints of REST. Also, if you stick with the default URI the CLR method names in the URIs become more like custom verbs again, instead of the noun-based approach we want to use with REST.

WCF 3.5 allows you to customize the URI for each CLR method. You can do this by customizing the UriTemplate property, which is a property on both WebGetAttribute and WebInvokeAttribute.

WebGetAttribute and WebInvokeAttribute annotate service operations (methods that include the OperationContractAttribute). These attributes form the base of the new dispatching model built into 3.5.

WebInvokeAttribute includes all of the same properties that WebGetAttribute has, but it also includes a Method property. WebGetAttribute is pretty obviously about which part of the uniform interface it implements: GET. The Method property indicates which verb (other than GET of course) the associated method will implement from the uniform interface. If the Method property isn't set, the default is POST. Table 2.1, "WebGetAttribute and WebInvokeAttribute properties" shows the properties of both WebGetAttribute and WebInvokeAttribute.

Table 2.1. WebGetAttribute and WebInvokeAttribute properties

Property name

Type

Default value

Description

BodyStyle

WebMessageBodyStyle

Bare

Specifies whether the request and the response data should be wrapped in an element with the same name as the CLR method name. Bare is typically used with RESTful services.

ResponseFormat

WebMessageFormat

Xml

Specifies the format for serializing the response.

RequestFormat

WebMessageFormat

Xml

Specifies the format for deserializing the request.

UriTemplate

string

null (assumed to be the name of the CLR method)

The definition of the URI the CLR method should respond to.

Method

string

null (assumed to be POST if null)

The HTTP verb the method should respond to (again this property is not on WebGetAttribute).


The UriTemplate property on WebGetAttribute is a simple string, but is arguably the most important property in the whole WCF web programming model. The string is going to be parsed into a type (also named UriTemplate) during the creation of the endpoint. This type is used at runtime to route messages to methods based on matching the template to the requested URI.

It makes sense to take a moment to look at the UriTemplate class in detail. It is important to get a good idea of its mechanics and how you can use it to your advantage when designing your services.

Note
Note that UriTemplate is in the System namespace even though the class is contained in the System.ServiceModel.Web.dll assembly.

UriTemplate enables you to make a template out of part of a URI by declaring a pattern-matching syntax. When passed a URI, the UriTemplate class parses the URI and determines if its pattern matches the URI. If the pattern matches, UriTemplate parses the matched parts into a data structure, indexed by order and possibly indexed by name (depending on the type of template used). This is a little bit like regular expression matching of a string, and although it's not quite as powerful as regular expressions, it doesn't really have to be. Let's start out with a URI example.

Imagine we had a web service that served up data about the biological taxonomy (e.g., Domain, Kingdom, Phylum, etc.). The URIs of this service should be:

http://example.org/Domain/Kingdom/Phylum/Class/Order/Family/Genus/Species

Users could specify any level of this hierarchy and get the data appropriate for that level. Some valid URIs would be:

  • http://example.org/

  • http://example.org/Eukaryote/Animalia

  • http://example.org/Eukaryote/Animalia/Chordata

  • http://example.org/Eukaryote/Animalia/Chordata/Mammalia/Carnivora/Canidae/Canis/C.%20lupus

  • http://example.org/Eukaryote/Animalis/Chordata/Felidae/Felis/F%20silvestris

The idea is to have each of these URIs return the appropriate data when an HTTP GET request is made to my service (we'll discuss the data format later in the chapter; for now we'll focus on the URIs). The service should return data that is appropriate for the specified hierarchy level. So, for example, if a user makes a request for the root, the service will return data about all the Domains (Archaea, Eubacteria, and Eukaryota), and if a user requests http://example.org/Eukaryote, the service will return data only about the organisms in the Eukaryote domain.

I'm going to use the following template string to make this URI scheme work with UriTemplate:

"/{Domain}/{Kingdom}/{Phylum}/{Class}/{Order}/{Family}/
{Genus}/{Species}"

Notice that the whole URI is not included in the template-only the path after the scheme, host, and port portion of the URI. The UriTemplate infrastructure assumes that part of your complete URI can and will probably change (as it would typically when you moved from dev to test to production as each environment would have a different host name). The curly braces between each level of hierarchy of the URI are the UriTemplate syntax. This syntax enables the UriTemplate to parse a particular URI for a match and, if a match is found, to bind the parts of the URI into a collection of variables.

Note
UriTemplate also includes wildcard capabilities. UriTemplate="*" (used in Example 2.7, "WCF 3.5 SimpleHTTPService implementation") will route all URIs to one method. The wildcard character can also be used at the end of a URI to allow a catch-all method for an unknown number of URI path segments (e.g., UriTemplate="/{Domain}/*"). The wildcard (*) must be either the only string or the last string in the UriTemplate-additional path segments aren't allowed after a wildcard.

Example 2.9, "Exercising UriTemplate" shows some of the code from a console application that attempts to match URIs based on UriTemplate.

Example 2.9. Exercising UriTemplate

Uri baseUri = new Uri("http://example.org");
UriTemplate template = new UriTemplate("/{Domain}/{Kingdom}/
{Phylum}/{Class}/{Order}/{Family}/{Genus}/{Species}");
Console.WriteLine("URI path segments are:");
foreach (var pathSeg in template.PathSegmentVariableNames)
{
    Console.WriteLine(pathSeg);
}
Console.WriteLine("type in a URI to test");
string uri = Console.ReadLine();
Uri testUri = new Uri(uri);
UriTemplateMatch match = template.Match(baseUri, testUri);
if (match != null)
{
    var bound = match.BoundVariables;
    string keyValue;

    foreach (var key in bound.Keys)
    {
        keyValue = key.ToString();
        Console.WriteLine("{0} = {1}", keyValue, bound[keyValue]);
    }
}
else
    Console.WriteLine("URI not a match");

The output of running this application is shown in Figure 2.4, "UriTemplate testing output based on Example 2.9, "Exercising UriTemplate".

Figure 2.4. UriTemplate testing output based on Example 2.9, "Exercising UriTemplate"

UriTemplate testing output based on

The code in Example 2.9, "Exercising UriTemplate" is pretty simple. It creates a UriTemplate instance, then prints all the path segments to the console. UriTemplate uses path segment internally for each part of the URI that is denoted by the curly braces ({}). The program will then receive input from the console and turn that input into a URI. Finally, the code will attempt to match the URI against the UriTemplate that was set with the hierarchy we are trying to parse.

Figure 2.5, "UriTemplate testing full URI" shows the results of passing in the URI http://example.org/Eukaryote/Animalia/Chordata/Actinopterygii/Siluriformes/Malapteruridae/Malapterurus/minjiriya.

Figure 2.5. UriTemplate testing full URI

UriTemplate testing full URI

When I type a string into a console and press Enter, the code takes the string and turns it into an URI. It then uses UriTemplate.Match to determine whether the URI matches the template definition. If there is a match, the returned UriTemplateMatch object can be used to inspect the results of the match, which would allow the code to use the matched path segment values. This program loops through the UriTemplateMatch.BoundVariables collection, which contains all the data that has been bound to each path segment. Table 2.2, "UriTemplateMatch properties" shows the complete list of UriTemplateMatch properties.

Note
In Chapter 10, Consuming RESTful XML Services Using WCF, when we talk about using WCF to invoke RESTful services, I'll show you how to turn UriTemplate around the other way-to get a full URI from a template by passing in the bound variables.

Table 2.2. UriTemplateMatch properties

Property

Type

Description

BaseUri

Uri

Contains the base URI passed to UriTemplate.Match

BoundVariables

NameValueCollection

A collection of name/value pairs, where the names are the path segments from the UriTemplate and the values are the parsed data

Data

Object

Arbitrary application-specific data that can be associated with a UriTemplate

QueryParameters

NameValueCollection

A name/value collection of items from the query string of the parsed URI

RelativePathSegments

Collection<string>

A union of the results of template matching and wildcard matching

RequestUri

Uri

The request URI passed to Match

UriTemplate

UriTemplate

A reference to the UriTemplate instance on which Match was called

WildCardPathSegments

Collection<string>

All the data that matched against the wildcard part of the UriTemplate (if any)


Compound Path Segments

Some RESTful services employ a URI feature known as compound path template syntax, which is useful when the URI resource you are modeling has more than one piece of data at a single level, or when you'd like to template the final URI extension. If, for example, you were working with the latitude and longitude of geographical locations, you might include the following in the UriTemplate:

"/{lat}/{long}"

However, it doesn't make much sense to have a URI formatted this way because longitude isn't part of a hierarchy under latitude. The general rule of thumb with URIs is that if there are multiple same-level pieces of data for a particular resource, and order matters, use a semicolon to separate them. If order doesn't matter, use a comma.

Unfortunately, WCF does not inherently support this type of functionality. If it did, the UriTemplate might look like the following for latitude and longitude:

"/{lat};{long}"

Another common practice is to expose different resource formats using the file extension:

"/map.json"
"/map.xml"

It would be nice to template these URIs like this:

"/map.{format}"

Chapter 7, Programming Ajax and Silverlight Clients discusses why this syntax might not be the optimal solution when using WCF when returning different media types (like JSON and XML) from the same method.

Because UriTemplate doesn't support either of these UriTemplate values in .NET 3.5, you can use the following workaround:

"/{latlong}"

You can then parse the data from the combined latitude/longitude string into its component parts by using String.Split or other string parsing mechanism. This is not an optimal solution, but at least WCF will not reject a particular path segment's data if it contains a comma or semicolon. I should also note here that WCF 3.5 SP1 adds additional support for compound path segments (see Appendix A, WCF 3.5 SP1).

If you pass an incomplete URI (a URI that doesn't contain all of the predefined levels) to the testing program, things don't go so well. Figures 2.6 and 2.7 show the results of passing http://example.org/ and http://example.org/Eukaryote, respectively.

Figure 2.6. Result of passing the root URI to UriTemplate

Result of passing the root URI to UriTemplate

Figure 2.7. Result of passing the first-level URI to UriTemplate

Result of passing the first-level URI to UriTemplate

From Figures 2.6 and 2.7, you can see that in order to consider a URI a match, UriTemplate requires a match on all of the path segments (assuming there is no wildcard in the template). So how do we deal with the problem of producing a URI that matches only the specified levels? This is precisely the function of the UriTemplateTable class.

UriTemplateTable is, as its name suggests, a table or collection of related UriTemplate objects. UriTemplateTable allows you to build up a collection of UriTemplate instances, and then run a match against the whole table. When you build up this table of UriTemplate instances, you associate each UriTemplate with an arbitrary (but hopefully useful) object. This object is then used to set the UriTemplateMatch.Data property if there is a match for a particular UriTemplate. The WCF infrastructure uses UriTemplateTable to store all the UriTemplate definitions for ServiceContract, and uses matches to route requests to methods based on a template match (as well as an HTTP verb match).

Right now, I am just going to use UriTemplateTable to illustrate how this works.

Example 2.10, "Using UriTemplateTable" represents version 2 of my code from Example 2.6, "WCF 3.5 version of Main". It creates an array of strings and a UriTemplate instance for each string. It then adds all the UriTemplate instances (and each UriTemplate's associated object) to a UriTemplateTable instance using its KeyValuePairs property. The code then includes a simple loop logic that waits for a URI and, when entered, tries to match that URI against the UriTemplateTable using UriTemplateTable.MatchSingle.

Note
UriTemplateTable also has a Match method that can return a collection of UriTemplateMatch instances if more than one UriTemplate matches. Using MatchSingle will cause the service to throw an exception if more than one UriTemplate matches, so if you plan to use MatchSingle, you should use UriTemplateTable to ensure only one UriTemplate will match.

Example 2.10. Using UriTemplateTable

string[] stemplates = new string[]{
"/",
"/{Domain}",
"/{Domain}/{Kingdom}",
"/{Domain}/{Kingdom}/{Phylum}",
"/{Domain}/{Kingdom}/{Phylum}/{Class}",
"/{Domain}/{Kingdom}/{Phylum}/{Class}/{Order}",
"/{Domain}/{Kingdom}/{Phylum}/{Class}/{Order}/{Family}",
"/{Domain}/{Kingdom}/{Phylum}/{Class}/{Order}/{Family}/{Genus}",
"/{Domain}/{Kingdom}/{Phylum}/{Class}/{Order}/{Family}/{Genus}/{Species}"
};
Dictionary<UriTemplate, object> templates =
  MakeTemplates(stemplates);
Uri baseUri = new Uri("http://example.org");
//create the UriTemplateTable
UriTemplateTable tt = new UriTemplateTable(baseUri);
//add all the UriTemplate/Value pairs to it
foreach (var kvp in templates)
{
    tt.KeyValuePairs.Add(kvp);
}
bool done = false;
while (!done)
{
    Console.WriteLine("type in a URI to test ('Q' to exit)");
    string uri = Console.ReadLine();
    if (uri == "Q")
    {
        done = true;
    }
    else
    {
        Uri testUri = new Uri(uri);
        UriTemplateMatch match = tt.MatchSingle(testUri);
        if (match != null)
        {
            Console.WriteLine(match.Data);
        }
        else
        {
            Console.WriteLine("No match found!");
        }
    }
}

Before discussing the execution of the program shown in Example 2.10, "Using UriTemplateTable", let's look at Example 2.11, "The MakeTemplates method", which is the method (called MakeTemplates) that I used to create the UriTemplate instances.

Example 2.11. The MakeTemplates method

static Dictionary<UriTemplate, object> MakeTemplates(string[] templateStrings)
{
    Dictionary<UriTemplate, object> templates =
     new Dictionary<UriTemplate, object>();
    UriTemplate uriTemplate = null;
    string msg = null;
    int lastPathSegment = 0;
    string segment = "ROOT";
    foreach (string template in templateStrings)
    {
        uriTemplate = new UriTemplate(template);
        if (uriTemplate.PathSegmentVariableNames.Count > 0)
        {
            lastPathSegment = uriTemplate.PathSegmentVariableNames.Count - 1;
            segment = uriTemplate.PathSegmentVariableNames[lastPathSegment];
        }
        msg = segment + " MATCH!";
        templates.Add(uriTemplate, msg);
    }
    return templates;
}

There isn't anything special about the MakeTemplates method in Example 2.11, "The MakeTemplates method", but it shows the logic I am using in my code to associate an object with each UriTemplate instance. Basically, the code creates a string that is logically associated with each URI you want to match. You can now use this new code to match against all the different URIs that are part of the logical URI scheme.

Figure 2.8. Using UriTemplateTable to match multiple URIs

Using UriTemplateTable to match multiple URIs

UriTemplateTable allows you to match multiple URIs at multiple levels in the same program. The output of Example 2.10, "Using UriTemplateTable" is shown in Figure 2.8, "Using UriTemplateTable to match multiple URIs".

Now, what if the string associated with each UriTemplate was the name of a method instead of just a string with no particular meaning? When a match is found, the code could dynamically invoke the associated method on a particular object. This is pretty much the way in which WCF 3.5 URI dispatching works. In WCF 3.5, WebHttpBehavior adds the object to the WCF server-side dispatching layer. WebHttpDispatchOperationSelector returns the name of the method selected (based on the UriTemplateMatch), and the IOperationInvoker invokes the method on the service instance object.

This implementation is inside the WebHttpDispatchOperationSelector type. It is the part of the WCF dispatching layer that determines which method is to be called on a service instance based on the UriTemplate match and the HTTP verb of the incoming request. The dispatcher keeps a special class (WCFLookupResult) that keeps track of which method is associated with a particular template and also which HTTP verb. I can't use WCFLookupResult because it is a private class (it's actually a nested class inside WebHttpDispatchOperationSelector), but I like knowing about it since it helps me to understand how the 3.5 dispatching model works. Here is the full definition of WCFLookupResult:

private class WCFLookupResult
{

    public WCFLookupResult(string method, string operationName);

    // Properties
    public string Method { get; }
    public string OperationName { get; }
}

As the WCF channel stack is opening, the WebHttpDispatchOperationSelector uses reflection on all the service methods on the contract associated with the current endpoint, and uses that information to construct the UriTemplateTable. It then adds a KeyValuePair instance for each method creating an UriTemplate and a WCFLookupResult. The UriTemplate comes from the UriTemplate property in either WebGetAttribute or WebInvokeAttribute. If WebGetAttribute is used, the WCFLookupResult.Method will be GET; otherwise, it's the value of WebInvokeAttri⁠bute.Method. The WCFLookup.OperationName is the name of the function on the service contract. This is how the WebHttpDispatchOperationSelector is able to implement its functionality.

UriTemplate Literal Values

Another UriTemplate feature that is worth mentioning is the capability to mix literal values with variable (path segment) values. In all of the preceding examples in this chapter, the UriTemplate has either been a wildcard value or a template in which all segments are variable values.

Building on the biological taxonomy example, imagine that instead of having all Domain requests routed to the same method, we want each discrete Domain value routed to its own method. Here's an example of using UriTemplate to mix literal and variable values to enable this type of dispatching:

UriTemplate levelOne = new UriTemplate("/Animalia");
UriTemplate levelTwo = new UriTemplate("/Animalia/{Kingdom}");

In this example, only those URIs containing the literal value Animalia as the first path segment after the base URI will be routed to the ProcessAnimalia method. URIs with the literal value Animalia will match on the first UriTemplate. URIs with the literal value Animalia followed by another path segment will be routed to the match on the levelTwo UriTemplate. In this way, you can combine literal values with variable path segments as dictated by your URI scheme.

Another thing you can do is use a string literal at a particular path level on one method when another method uses a variable path segment at that same level. For example, to expose a special resource under the /Animalia resource, change the code to:

UriTemplate levelOne = new UriTemplate("/Animalia");
UriTemplate levelTwo = new UriTemplate("/Animalia/{Kingdom}");
UriTemplate specialLevel = new UriTemplate("/Animalia/special");

There is now a third UriTemplate, which extends the top-level template, but it has a literal path segment instead of a variable path segment. According to the rules of UriTemplateTable matching, any URI with Animalia and another path segment that isn't the literal value special will continue to match on the UriTemplate with the variable name of levelTwo that has the variable path segment. If the literal value special is the value of the path segment in a URI after the segment with the literal value Animalia, the UriTemplate named specialLevel (the third one in this list) will be a match. This rule comes in handy when special-casing a particular path segment literal value. You could just use a variable path segment and check the value of the variable path segment in the levelTwo template match for the literal value special, but since WCF can handle that for you, you can partition your code into two methods and instead of having to write the conditional code yourself, WCF will conditionally route the request automatically.

UriTemplate Special Values

Two special characters for UriTemplate are what I call the root template and the wildcard template.

The first UriTemplate in the UriTemplateTable in Example 2.10, "Using UriTemplateTable" uses the root template, which is simply the forward-slash character:

UriTemplate root = new UriTemplate("/");

This template is used quite often in a RESTful service to represent the root resource of a particular hierarchy, or the factory URI for creating new resources.

The other special template, the wildcard template, uses the wildcard character (*), either alone or in conjunction with literal and variable path segments. When the wildcard character is used alone, UriTemplate will match every URI:

UriTemplate matchAll = new UriTemplate("*");

UriTemplate QueryString

Yet another UriTemplate feature is the capability to parse the path portions of the URI along with the QueryString. Conventional wisdom is that the QueryString should be reserved for indicating to the client that the data being passed includes algorithm variables rather than resource hierarchy variables.

To illustrate this capability, imagine a RESTful endpoint with search capabilities. Which URI makes more sense, a or b?

a) http://example.org/search/Don%20Box
b) http://example.org/search?q=Don%20Box

Sometimes URI design is based on aesthetics, and in this case, I prefer option b. Also, option b follows the convention of having resources that perform algorithms take parameters as query parameters.

The URIs in both options could be parsed successfully with UriTemplate, but I prefer the syntax to support option b):

UriTemplate search = new UriTemplate("/search={y}");

Contrast this to the syntax to support option a:

UriTemplate search = new UriTemplate("/search/{q}");

Again, both options will accomplish the same thing (that is, route the request to the Add method and pass both x and y to the method), but the QueryString version just feels better because x and y aren't part of the resource, they are just values being passed to a resource.

In this chapter you learned about the basic functionality of the new WCF 3.5 programming model, and how that model builds on the extensibility of the basic WCF channel stack. WCF 3.5 includes several features that enable you to build RESTful services, including WebHttpBinding, which creates a channel stack that will support HTTP programming with variable URIs (and without any hint of SOAP).

  • WebServiceHost provides an easy hosting environment for RESTful services, and adds the WebHttpBinding and WebHttpBehavior to service endpoints automatically.

  • WebHttpBehavior replaces the default dispatching infrastructure of WCF, which is based on routing messages to CLR methods based on the SOAP action header. Instead, WebHttpBehavior allows routing of messages to CLR methods based on the URI and the HTTP verb.

  • WebGetAttribute and WebInvokeAttribute operation behaviors are the pieces of the infrastructure that enable annotating CLR methods on the service contract type with the information used by the new dispatching layer. This allows incoming network requests to be routed to the correct method on your service instance. The WebGetAttribute indicates the CLR method will response to HTTP GET requests. When a method has the WebInvokeAttribute associated, the W⁠e⁠b⁠I⁠n⁠v⁠o⁠k⁠e⁠A⁠t⁠t⁠r⁠i⁠b⁠u⁠t⁠e.M⁠e⁠t⁠h⁠o⁠d property indicates which part of the uniform interface that method will respond to. The UriTemplate facility adds to this functionality by also allowing customization of the URI for each service method, with the variable path segments and query string capabilities to customize the URIs for RESTful services.

Now that I've shown you the basics of the REST architectural constraints, and the basics of how WCF provides a programming model for those constraints, I can start to show you how to build services using both.

Show:
© 2014 Microsoft. All rights reserved.