WCF Syndication

HTTP Programming with WCF and the .NET Framework 3.5

Justin Smith

This article is based on a prerelase version of Visual Studio 2008. All information herein is subject to change.

This article discusses:

  • HTTP message basics
  • Adding information to URIs
  • WCF and HTTP
  • RSS and ATOM with WCF
This article uses the following technologies:
Windows Communication Foundation

Contents

HTTP Message Basics
Expressing Additional Information
REST and the Web
HTTP Programming with WCF
HTTP Verbs in WCF Contracts
Binding and Hosting
The New Syndication API
Creating a SyndicationFeed
Tying It All Together

When it was first released as part of the Microsoft®.NET Framework 3.0, Windows®Communication Foundation (WCF) included a universal object model for Plain Old XML (POX) and SOAP messaging over a wide variety of transports. Because WCF also contains deep support for WS-* Web service standards, it is able to interoperate with other modern service platforms with relatively little difficulty. WCF in the .NET Framework 3.0 is highly extensible and includes solid manageability features like message logging, activity tracing, service throttling, instance management, and threading controls.

WCF in the .NET Framework 3.5 builds on the extensibility points in the .NET Framework 3.0 to include first-class support for building services that adhere to the principles of the Web. This includes an easy-to-use HTTP programming model, JavaScript Object Notation (JSON) messaging capabilities, and a new syndication API that makes it easy to create and consume syndicated content. With this feature set, WCF is now the service platform of choice for connecting services to Web clients, whether they are ASP.NET AJAX controls, SilverlightTMclients, or even browsers. These features also work in partial trust scenarios (like ASP.NET medium trust) so you can host WCF services in widely available hosting environments. To round it all out, there's also new tooling integrated into Visual Studio®2008 that dramatically reduces the amount of time it takes to get a service up and running.

Combining Web-centric communication with SOAP and WS-* standards into one service stack and object model is one of the features that makes WCF in the .NET Framework 3.5 so compelling. This means you can build a service that communicates within or across enterprise boundaries using SOAP and WS-*, and you can configure that same service to communicate externally using the protocols of the Web. In effect, WCF takes care of the plumbing in your service and lets you focus more closely on the functionality your service exposes.

This article explains some of the new Web-centric features of WCF in the .NET Framework 3.5. It starts with a level-setting discussion about some of the important architectural principles in HTTP and the Web, then moves to the new HTTP programming model in WCF, and, finally, to the new syndication API.

HTTP Message Basics

You probably use the Web almost every day, but how often do you think about the core concepts that make the Web work? It's not in my nature to carry on about architectural concepts, but some of the key ideas baked into the Web may not be obvious at first glance. In my view, a good understanding of these principles is a necessary first step when building services that adhere to the protocols of the Web. Keep in mind that entire books are dedicated to this topic, so I'll only hit the high points in this article. When in doubt, consult the HTTP/1.1 specification (RFC 2616).

HTTP is the native protocol that runs the Web. HTTP is a request/response protocol: every time you use your browser to navigate to a new Web page, you send an HTTP request message to an HTTP server (or proxy), which will return a response message to your browser. HTTP defines several methods (often called verbs informally) that identify operations that an HTTP server can perform (for example, GET, POST, PUT, and DELETE). The HTTP protocol also defines the notion of a resource that is the “target” of the request. Resources are identified by a URI which appears as data in the HTTP request message. Here is a trimmed down version of an HTTP request:

POST /myservice/PostAlbum HTTP/1.1 
HOST: www.cloudsample.net 
Content-Type: text/xml 

<albumInfo> <albumId>15</albumId> </albumInfo>

In this example, the resource URI is https://www.cloudsamples.net/myservice/PostAlbum and the HTTP method is POST. POST is the most common HTTP method for causing side-effects and has the most “liberal” interpretation in the protocol specification (and in common practice). The request message also has an XML payload (also known as the “entity body”) that contains a value for the albumId field.

The POST method is most commonly used for updating data over the web. However, most web traffic simply reads information, which happens using the GET method. A GET request asks for a data value (called a representation) that corresponds to the specified URI. Here’s a simple HTTP GET request:

GET /myservice/GetAlbum/15 HTTP/1.1 
HOST: www.cloudsamples.net

GET requests have no payload – rather, the request consists solely of the request URI plus headers. In general, headers are used for content negotiation and cache management, with the URI containing the “significant” information needed to identify the resource in question. This emphasis on the URI is a recurring theme in web-centric applications.

HTTP response messages contain a status code, zero or more headers, and an optional payload/entity body. HTTP status code tells the client what happened, and the headers and payload convey the response information. Here’s a simple HTTP response that corresponds to our GET request above:

HTTP/1.1 200 OK 
Content-Type: text/xml 
Expires: Thu, 01 Jan 2009 13:00:00 GMT 

<Album id="15" title="The rest of the story" />

This response indicates that the request was successfully processed (hence the 200 status code) and that the representation of the resource is the XML value that appears in payload. The Expires header indicates that this response can be cached until 1PM January 1, 2009. The value of standardized cache management headers is that web infrastructure (e.g., proxies, client software) can reduce network traffic and processing cost by satisfying GET requests without a full client-server round-trip (and subsequent server processing costs). For a great treatment on how HTTP cache management works, go to Mark Nottingham’s tutorial at https://www.mnot.net/cache\_docs/

Expressing Additional Information

Applications that receive an HTTP GET use the information embedded in the URI to determine which resource to send as a reply. To illustrate, consider this set of URIs:

contoso.com/artists/Flaming+Hammer/HitMe 
contoso.com/artists/Northwind/Overdone

In this case, Contoso Corporation has an application that serves resources related to music. You can probably deduce from these examples how the name of the artist and the name of the album can map into a URI:

contoso.com/artists/[artist]/[album]

When the application receives an HTTP GET message for https://contoso.com/artists/Northwind/Overdone, it should return a resource related to Northwind's Overdone album. There's clearly a pattern to the URI. It consists of some base information (contoso.com/artists) and some URI segments (or "holes") that will contain the values of the artist and album.

It is also common to embed the same sort of information in query string parameters. Though the format is different from the previous examples, the end result is the same. Here is a set of URI holes with a query string parameter:

contoso.com/artists/Flaming+Hammer?album=HitMe 
contoso.com/artists/Northwind?album=Overdone

In this case, the URI and the query string are using the following syntax:

contoso.com/artists/[artist]?album=[album]

HTTP uses an extensible set of headers for expressing additional information. This information can be related to caching, the type of data in the message, the name of the sending application, the length of the content, the host operating system, and much more. Figure 1 shows an HTTP GET message (lines 1-8) and the reply message (lines 9-14) with several common headers.

Figure 1 HTTP GET Request and Response

GET /PictureServices/Feed.svc/picture/Pictures;Bridge.jpg HTTP/1.1 
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel,application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, application/x-silverlight, */* 
Accept-Language: en-us 
UA-CPU: x86 
Accept-Encoding: gzip, deflate 
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 3.5.20706; .NET CLR 3.0.590; MS-RTC LM 8) 
Host:www.cloudsamples.net 
Proxy-Connection: Keep-Alive
HTTP/1.1 200 OK
Content-Type: image/jpeg 
Server: Microsoft-IIS/7.0  
X-Powered-By: ASP.NET
Date: Sat, 15 Sep 2007 18:57:11 GMT
Content-Length: 106333

The Accept header in the HTTP GET request indicates which data formats the client would like to receive. As you can see from the long list of values, the client can receive several kinds of data (images, office documents, Silverlight apps, and so on). The response to the HTTP GET contains data whose format is described by the value of the Content-Type header (image/jpeg as shown on line 10). This simple mechanism allows the sending and receiving application to coordinate data formats. Using MIME types in headers for data format coordination is not as expressive as the Web Services Description Language (WSDL) and XML Schema Definition (XSD) grammars of SOAP Web services, but it's enough for the Web.

REST and the Web

By looking at some key parts of HTTP, you have also seen some of the important principles that hold the Web together. In 2000, a PhD student named Roy Fielding finished a dissertation that, among other things, codified these principles into an architectural style known as Representational State Transfer (REST). (You can find Roy's dissertation atics.uci.edu/~fielding/pubs/dissertation/top.htm.)

Books, software conferences, and a seemingly innumerable collection of blogs have discussed the REST architectural style in fine-grained detail. It's not possible to cover all of its facets here, but the important principles to take away are:

  • Embrace the URI
  • HTTP GET is special
  • Content-Type is the data model

By baking these principles into your applications, you dramatically increase the interoperability and reach of your application's functionality. Interoperability and reach are key drivers behind most Web services initiatives. After all, a Web service is really a way to expose some functionality via a structured messaging scheme. The principles of the Web (HTTP request/response) are actually describing a subset of possible messaging schemes. Practically all platforms, applications, operating systems, and users understand the principles of the Web, so embracing them in your Web service application gives it improved reach and interoperability.

HTTP Programming with WCF

Building on the foundation of these Web basics, let's take a look at using WCF in the .NET Framework 3.5 to build applications that adhere to the principles of the Web. I'll start by examining some of the new building blocks of the HTTP programming model and progress upwards through the system.

If you're going to "embrace the URI," you will probably have to get used to building and parsing URIs. When done by hand, this task is error-prone and tedious. However, the new System.UriTemplate and System.UriTemplateMatch types do the heavy lifting of creating and parsing URIs, and are some of the fundamental building blocks for the new HTTP capabilities of WCF.

The UriTemplate type is the basic building block for defining the URI holes discussed earlier. The constructor of the UriTemplate type accepts a String that represents the holes in a URI. Once instantiated, a UriTemplate object exposes two instance methods for binding text values to the holes defined at instantiation. These methods return a URI whose holes are populated with values.

A UriTemplate object also exposes an instance method named Match for extracting the values of the holes of a System.Uri object. The Match instance method accepts two System.Uri objects. The first Uri is a base address, and the second Uri is candidate for matching. A System.UriTemplateMatch object is returned from the Match method. The UriTemplateMatch object contains a collection of values for the holes defined at UriTemplate instantiation time.

The code in Figure 2 illustrates how to use the UriTemplate and UriTemplateMatch types to round-trip a Uri. The result of this code is the following output:

Figure 2 Creating a Template-Based URI

// create a URI bound to the template 
Uri baseAddress = new Uri(@
"https://localhost:2000");
UriTemplate template = new UriTemplate("{artist}?album={album}");
Uri boundUri = template.BindByPosition(baseAddress, "Northwind", "Overdone");
Console.WriteLine(boundUri.ToString()); // retrieve the value of the artist segment
UriTemplateMatch match = template.Match(baseAddress, boundUri);
String bandName = match.BoundVariables["artist"];
Console.WriteLine("the name of the artist is {0}", bandName);

http: //localhost:2000/Northwind?album=Overdone the name of the artist is Northwind

The System.UriTemplate and System.UriTemplateMatch types are missing the usual WCF System.ServiceModel moniker in the namespace. That's because their functionality is such that you don't have to use them inside a WCF application. They are quite handy anytime you need to create or parse a URI.

Though the UriTemplate and UriTemplateMatch types are quite easy to use, the WCF team wanted to make it even easier to use these two types in a WCF service. The goal was to offer a simple and intuitive way to map URI segments and query string parameters into application functionality. I think the model as shown in the following code fits the bill:

[ServiceContract] public interface IPictureService {
    [OperationContract][WebGet(UriTemplate = "picture/{pictureId}")] Stream GetPicture(String pictureId);
    [OperationContract][WebGet(UriTemplate = "picture/t/{pictureId}")] Stream GetPictureThumbnail(String pictureId);
}

The UriTemplate surfaces as an instance property on the WebGetAttribute, which, in turn, is applied to a service contract. Notice that the token between the curly braces maps to the name of the method parameter. Though this sample shows only one parameter, you can add many parameters, arrange them in any order, add them as query string parameters, and even use wildcards.

At run time, the value of the UriTemplate property is passed to the UriTemplate constructor. Both the Client runtime and the Dispatcher use the UriTemplate property value in this manner. The Dispatcher uses it to match incoming messages to an operation, and the Client uses it to ensure that a method on a proxy gets sent to the right URI. It's an easy-to-use, simple, and effective way to "embrace the URI" in your services.

HTTP Verbs in WCF Contracts

Additional Resources

HTTP programming with WCF in the .NET Framework 3.5 makes it easy to map operations in a service contract to HTTP verbs. As you can probably tell from the name, applying the WebGetAttribute to an operation makes that operation available via an HTTP GET. As you saw in the previous code snippet, the WebGetAttribute defines an instance property named UriTemplate.

There are other instance properties on the WebGetAttribute type. The most notable are RequestFormat and ResponseFormat. As their names imply, the values of these properties dictate the message format for the operation. The RequestFormat and ResponseFormat properties are of type WebMessageFormat, an enumerated type that has two values: Xml and Json. The WCF infrastructure uses the values of these properties to set up the channel stack with the appropriate message encoder. A property value of WebMessageFormat.Xml will result in a channel stack that uses the XML encoder. Setting the value to WebMessageFormat.Json will result in a channel stack that uses the JSON encoder included in the .NET Framework 3.5. Since there are properties for both sides of the HTTP message exchange, it is possible for an application to receive an XML message and return a JSON message (or vice-versa).

The other attribute related to HTTP verbs is WebInvokeAttribute. Applying this attribute to an operation makes that operation available by any HTTP verb other than HTTP GET. The separation in the object model between HTTP GET and all other verbs reflects the frequency HTTP GET is used versus the other HTTP verbs. The WebInvokeAttribute object model is similar to the WebGetAttribute, but it includes an instance property named Method. The value of this property associates a particular HTTP verb to the operation. The Method property is of type String, so you can set the value to any standard HTTP verb, and even non-standard HTTP verbs. Figure 3 illustrates how to use the WebInvokeAttribute in a service contract.

Figure 3 Using WebInvokeAttribute

[ServiceContract] public interface IPictureService {
    [OperationContract][WebGet(UriTemplate = "picture/{pictureId}")] Stream GetPicture(String pictureId);
    [OperationContract][WebGet(UriTemplate = "picture/t/{pictureId}")] Stream GetPictureThumbnail(String pictureId);
    [OperationContract][WebInvoke(UriTemplate = "update", Method = "POST")] void UpdatePictureInfo(PictureInfo info);
}

The UpdatePictureInfo method has a parameter of type PictureInfo. At run time, a serialized version of a PictureInfo object is the payload of an HTTP POST message. Passing data this way allows applications to ship complex data types that are not otherwise expressible in a URI.

WCF in the .NET Framework 3.5 also makes it easy to interact with HTTP headers. Request and response HTTP headers are exposed via the System.ServiceModel.Web.WebOperationContext type. The WebOperationContext type is an extension of the System.ServiceModel.OperationContext type introduced in WCF in the .NET Framework 3.0, and its usage pattern is similar. Both are intended to be used within the implementation of a service object. The WebOperationContext type exposes members that simplify reading or setting HTTP header values, as well as retrieving information about the URI used to access the service object. The HTTP headers are stored as a collection, and the most common ones are exposed as individual properties. This example shows how to use the WebOperationContext type to follow the data model of the Web by setting the Content-Type header for an HTTP response:

public Stream GetPicture(string pictureId) { // retrieve the Stream (omitted) 
    Stream stream; // set the Content-Type to image/jpeg 
    WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
    return stream;
}

Binding and Hosting

So far, you've seen how to map URI segments to application functionality, how to map operations to HTTP verbs, and how to interact with HTTP headers. Now let's see how to connect these features together into a functioning service. To do this, you'll need to look at a few more types that are new in WCF.

WCF in the .NET Framework 3.0 introduced the concept of a binding, the abstraction over the transport and protocols of an endpoint. The .NET Framework 3.0 shipped with several bindings that included support for a wide array of transport and protocol choices.

WCF in the .NET Framework 3.5 includes a new binding named System.ServiceModel.WebHttpBinding. This binding is the abstraction of the principles of the Web and follows the same usage model as the binding types in the .NET Framework 3.0, so you can add it to an endpoint just like you would any other binding.

WCF in the .NET Framework 3.0 also introduced the concept of an endpoint behavior. A behavior is a way to extend the execution path of the messaging infrastructure. There are several behaviors that ship with the .NET Framework, and it is also easy to create your own.

WCF in the .NET Framework 3.5 includes a new endpoint behavior named System.ServiceModel.Description.WebHttpBehavior. This behavior does several tasks. For receiving applications, it sets up the filtering infrastructure to ensure, among other things, that received messages are dispatched to the appropriate method on the service object. In the .NET Framework 3.0 WCF used a combination of SOAP Action and target address as dispatch keys. The filtering mechanism setup by the WebHttpBehavior extends the existing filtering mechanisms to key off of UriTemplate matches and HTTP verbs.

Figure 4 shows how you can use WebHttpBinding and WebHttpBehavior to build a receiving application that embraces the principles of the Web. The advantage of this approach is that you can add one of these endpoints to an existing ServiceHost and by doing this you end up with one ServiceHost that has both SOAP/WS-* endpoints and REST endpoints.

Figure 4 Using WebHttpBinding and WebHttpBehavior

ServiceHost host = new ServiceHost(typeof(IPictureContract), 
  new Uri("https://localhost:5000"));
// instantiate a WebHttpBinding 
WebHttpBinding binding = new WebHttpBinding();
// add an endpoint, using the WebHttpBinding 
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IPictureContract), 
  binding, String.Empty);
// add the WebHttpBehavior to the endpoint 
ep.Behaviors.Add(new WebHttpBehavior());
// open the ServiceHost to start listening 
host.Open();

Sending applications follow the same usage model, but the WebHttpBehavior should be added to the endpoint behavior collection on the ChannelFactory<T> object. As per typical WCF practice, these options are also available in configuration files.

WCF in the .NET Framework 3.5 takes this easy-to-use model even further so that you don't have to add either WebHttpBinding or WebHttpBehavior in some cases. The new API includes two types that serve this purpose: System.ServiceModel.Web.WebServiceHost and System.ServiceModel.Web.WebServiceHostFactory. The WebServiceHost type automatically adds the WebHttpBehavior to all endpoints and does some extra validation at run time to ensure that all endpoints are compatible with the behavior. This saves you the step of adding the WebHttpBehavior to an endpoint.

The WebServiceHostFactory type was designed for use in IIS-hosted scenarios to remove the need for any imperative or configuration file hosting information. WCF in the .NET Framework 3.0 introduced the .svc file as an activation target for hosting WCF services in IIS. These files contain directives that look similar to page directives in ASP.NET. Adding WebServiceHostFactory to the Factory property of the .svc file directive creates a ServiceHost, adds an endpoint that uses the appropriate contract with the WebHttpBinding, adds WebHttpBehavior to that endpoint, and opens the ServiceHost:

<%@ ServiceHost Language="C#" Service="PictureService" 
  Factory="System.ServiceModel.Web.WebServiceHostFactory" %>

The web.config file for the service does not contain any WCF-related entries.

The New Syndication API

Imagine an RSS feed. If you are at all like me, you immediately think of a news feed or a blog. Syndications—RSS and ATOM are syndication formats—are able to express much more. In the abstract, syndicated content is simply a way to represent a set of data. That set of data could be practically anything: the number of wombats in residence within a 50-mile radius of Sydney, the last 10 purchase orders over $100, or the number of boomerangs Contoso produced last month.

The .NET Framework 3.5 includes rich support for creating and consuming syndicated content. It supports creating and consuming both RSS 2.0 and ATOM 1.0 formats, various means of adding syndication extensions, and even the capability to implement additional formats. The programming model shields the developer from syndication format particulars, thereby helping to make it easy to use.

Up until version 3.5, there was no standard way to create or consume syndicated content with the .NET Framework. Though the new syndication functionality was written by the WCF team, it is not dependent on WCF. In fact, all of the syndication-related types are part of the System.Syndication namespace, though they reside in the System.ServiceModel.Web.dll assembly. You can use the syndication capabilities of the .NET Framework 3.5 from any process that hosts an AppDomain (ASP.NET, WPF applications, NT Services, and so on). This capability implies that you can serve or consume syndicated content over any transport, not just HTTP. However, when coupled with the HTTP programming model in WCF, you can add syndication to existing SOAP/WS-* services as well.

The new syndication API includes types that abstract an individual syndication feed and the items in a feed, as well as types that can transform that feed into a particular format. The System.Syndication.SyndicationFeed type is a format-neutral representation of a syndication feed. A SyndicationFeed contains a list of SyndicationItem objects. A SyndicationFeed without a set of SyndicationItem objects is like a pod without any peas, because a SyndicationItem object is just a representation of an item in a feed.

Once a SyndicationFeed has been populated with a set of SyndicationItem objects, a SyndicationFeedFormatter<T> can transform that feed into a particular format. There are two types derived from SyndicationFeedFormatter<T>: Rss20FeedFormatter and Atom10FeedFormatter. As their names imply, these types transform an instance of a SyndicationFeed into the RSS 2.0 and ATOM 1.0 formats, respectively.

Creating a SyndicationFeed

There are two ways to create a SyndicationFeed object. You can instantiate one and populate its members manually, or you can populate the entire SyndicationFeed from an existing feed. Both are easy to do and shield the developer from the quirks of a particular wire format. This code demonstrates how to build a SyndicationFeed object manually.

SyndicationFeed feed = new SyndicationFeed(); 
feed.Title.Text = "The Cybertopian Chronicle";

Title is just one of many properties you can set, so check the documentation for additional possibilities.

It is often the case that you want to read an existing feed and do something based on the contents of that feed. In the new syndication API, you can instantiate a SyndicationFeed and automatically populate its state from an existing feed. All you need to start is the URI of the existing feed or an XmlReader that's poised to read one. This code shows how to connect to an existing feed on the Web and extract some information from it:

Uri feedUri = new Uri("https://blogs.msdn.com/justinjsmith/atom.xml");
SyndicationFeed feed = SyndicationFeed.Load(feedUri);
Console.WriteLine(feed.Title.Text);
// outputs "The Cybertopian Chronicle"

The SyndicationItem type contains more than 35 members. Many of these are properties related to setting or retrieving fields like the item identifier, last updated time, published date, title, or the actual content. There are also numerous members that make it easy to extend the content stored in a SyndicationItem. There are many extensions to RSS and ATOM (Microsoft Simple List Extensions, Yahoo Media RSS, and GeoRSS, among many others), and both SyndicationFeed and SyndicationItem can be extended to include any existing RSS or ATOM extension.

Feeds can have many items, and loading them all at once is not an option for large feeds. The SyndicationFeed addresses this situation by exposing its set of SyndicationItem object as an IEnumerable<SyndicationItem>. This implementation makes it easier to deal with large numbers of SyndicationItem objects because it leverages the iterator capability of the .NET Framework 2.0. It's also possible to iterate over a set of SyndicationItem objects using LINQ. This can dramatically reduce the amount of code required to extract information from a feed.

The syndication API defines several types that transform a SyndicationFeed into the RSS 2.0 and ATOM 1.0 formats. In fact, you can build one SyndicationFeed, populate it with SyndicationItem objects, then expose that feed as both RSS and ATOM. Figure 5 demonstrates how to retrieve an ATOM 1.0 feed, transform it to RSS 2.0, and output the new RSS representation to the console.

Figure 5 Transforming a Feed

// read an ATOM feed 
Uri feedUri = new Uri("https://blogs.msdn.com/justinjsmith/atom.xml");
SyndicationFeed feed = SyndicationFeed.Load(feedUri);
// transform it to RSS 
Rss20FeedFormatter formatter = new Rss20FeedFormatter(feed);
XmlWriter writer = XmlWriter.Create(Console.Out, null);
// write it to the Console 
formatter.WriteTo(writer);
writer.Flush();

When you partner the syndication API with the HTTP programming model in WCF, you are able to expose a feed from a customized URI and return RSS or ATOM based on the composition of that URI. Figure 6 shows how to define an operation in a service contract that uses a query string parameter from a received HTTP GET to return either an RSS or an ATOM feed. Notice the use of the SyndicationFeedFormatter<SyndicationFeed> in the operation contract. Both Rss20FeedFormatter and Atom10FeedFormatter derive from SyndicationFeedFormatter<TSyndicationFeed>.

Figure 6 Exposing a Feed from a Customized URI

[ServiceKnownType(typeof(Atom10FeedFormatter))]
[ServiceKnownType(typeof(Rss20FeedFormatter))]
[ServiceContract] interface IPictureService {
    [OperationContract][WebGet(UriTemplate = "Pictures?format={format}")] 
                 SyndicationFeedFormatter < SyndicationFeed > Feed(String format);
}
class PictureService: IPictureService {
    public SyndicationFeedFormatter < SyndicationFeed > Feed(String format) {
        // create the syndication feed 
        SyndicationFeed feed = new SyndicationFeed();
        // add the items to the feed (omitted) 
        // check the argument & return the right format 
        if (format.ToLower() == "rss") {
            return new Rss20FeedFormatter(feed);
        }
        return new Atom10FeedFormatter(feed);
    }
}

Tying It All Together

To summarize, you've seen some of the basics of HTTP, how this relates to principles of the Web, how to use WCF to bake those principles into your application, and how to use the new syndication API to serve and consume RSS and ATOM feeds. To further demonstrate the capabilities of these new features, you can see them running together in a sample application called PictureServices at www.cloudsamples.net/pictureservices. You can run the sample online, browse the source code, and download the entire sample. Figure 7 shows PictureServices in action.

Figure 7 The PictureServices Feed

Figure 7** The PictureServices Feed **(Click the image for a larger view)

In a nutshell, PictureServices can retrieve pictures from a local machine or from a Flickr feed. The application uses a simple provider model, and there are currently three providers: Windows Desktop Search, a folder on your file system, and Flickr. Once PictureServices retrieves the files from a provider, it syndicates those pictures and serves them locally. From a browser you can click through a feed and retrieve individual pictures. There's quite a bit more in the sample, so feel free to explore. For links to more information about the technologies discussed here, see the "Additional Resources" sidebar in this article.

Justin Smith works at Microsoft as a Technical Evangelist devoted to Web services. His areas of focus are WCF and BizTalk Services. Justin is also the author of Inside Windows Communication Foundation (Microsoft Press, 2007) and a frequent presenter at software development conferences. Read his blog at blogs.msdn.com/justinjsmith.