WCF 3.5: Syndication Feeds

4. March 2008 12:09

In .NET 3.0, WCF did not have any built-in support for syndication feeds, such as RSS and ATOM.  As a result, it was necessary to roll your own solution anytime you wanted to render a syndication feed from your service.  While this wasn't an incredibly difficult task, it was still rather tedious.      Fortunately, .NET 3.5 introduced rich support for easily enabling syndication feeds from your service with relatively little effort.  Overall, it does a great job of handling the dirty work for you.  Let's take a look at how to set it up.

For this example, let's say that you have a WCF service that provides product information.  We want to enhance this service to provide an RSS/ATOM feed containing the product information.  The first thing we need to do is setup our service contract. 

[ServiceContract(Namespace = "JeffBarnes.Samples.Syndication")]
[ServiceKnownType(typeof(Rss20FeedFormatter))]
[ServiceKnownType(typeof(Atom10FeedFormatter))]
public interface IProductService
{
    [OperationContract]
    [WebGet(UriTemplate = "/product/{code}")]
    Product GetProduct(string code);

    [OperationContract(Name = "GetAllProducts")]
    [WebGet(UriTemplate = "/products?format={format}")]
    SyndicationFeedFormatter GetProductSyndicationFeed(string format);

    [OperationContract(Name = "GetProductsByCategory")]
    [WebGet(UriTemplate = "/products/{category}?format={format}")]
    SyndicationFeedFormatter GetProductSyndicationFeed(string category, string format);
}

If you are familiar with WCF services, the ServiceContract and OperationContract attributes should already be familiar to you.  Depending upon whether you have written many advanced services, you may also be familiar with ServiceKnownType.  If not, it is essentially used to inform the WCF runtime that it needs to be aware of a specific type for the purpose of serialization.

The WebGet attribute is a newcomer in .NET 3.5.  It is part of the new REST stack.  I have already written about WebGet in a previous post.  You should refer to it for a more thorough overview.  The abridged version is that it allows the WCF runtime to dispatch HTTP GET requests that match the specified UriTemplate to the given method.  As you can probably discern from the code, the GetProductSyndicationFeed method returns a feed of products in a specified format (RSS or ATOM).

So, what does the implementation look like?  I'm going to trim it down to the most interesting pieces for the sake of brevity.

// Create the syndication items from the products.
IEnumerable<SyndicationItem> items =
    from product in products
    orderby product.Code
    select new SyndicationItem(...);

// Create the syndication feed.
SyndicationFeed feed = new SyndicationFeed(
    "Jeff's Product Catalog",
    feedDesc,
    WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri,
    items);

// Determine the format to use.
SyndicationFeedFormatter formatter = null;
if (String.Compare(format, "rss", true) == 0)
{
    formatter = new Rss20FeedFormatter(feed);
}
else
{
    formatter = new Atom10FeedFormatter(feed);
}

return formatter;

First, a LINQ query is used to construct an enumerable collection of SyndicationItems based upon the product information.   SyndicationItem offers a lot of flexibility and extensibility.  It provides seamless support for formatting your content as html, xml, or custom formats.  Next, the SyndicationItems are supplied to a SyndicationFeed that decorates the items with some other information.  Ultimately, the SyndicationFeed is wrapped by a feed formatter.  Depending upon the requested format, either RSS or ATOM will be used.

There is one last gotcha to keep in mind in regards to the hosting of the service.  In order to enable the REST stack, there is a specific binding and behavior that must be used:  webHttpBinding and webHttpBehavior.  You can manually set these up via configuration.  However, there is a new ServiceHost subclass available that offers a configuration free alternative.  Check out the following snippet:

using (WebServiceHost host = new WebServiceHost(typeof(ProductService), new Uri("http://localhost:8000/ProductService")))
{
    host.Open();
    Console.WriteLine("Service Ready");
    Console.Read();
}

WebServiceHost will automatically create an endpoint with the necessary binding and behavior to enable the REST stack.  I don't even have a configuration file in this demo.  The only configuration code is what is shown above.  If you are using IIS to host your service, you can still use WebServiceHost, but it requires referencing System.ServiceModel.Activation.WebServiceHostFactory from your SVC file.

Once you get everything wired together, it's as easy as typing a URL into your web browser of choice and viewing the results.  Most browsers are aware of syndication feeds and apply special formatting to them.  For example, here is a screen shot of IE when you hit http://localhost:8000/productservice/products/Beverage for the demo.

I have barely scratched the surface of the capabilities of the syndication infrastructure in WCF, but this example effectively demonstrates how little effort is required to get started.  I'll probably do some additional posts on some of the more advanced syndication abilities at some point in the future. 

You can download the complete sample here.

Comments

8/7/2013 7:16:43 AM #

pingback

Pingback from hirendhara.biz

How to improve my solution for Rss/Atom using SyndicationFeed with ServiceStack? | Q Sites

hirendhara.biz |

Comments are closed

About Me

I'm a passionate software developer and advocate of the Microsoft .NET platform.  In my opinion, software development is a craft that necessitates a conscious effort to continually improve your skills rather than falling into the trap of complacency.  I was also awarded as a Microsoft MVP in Connected Systems in 2008, 2009, and 2010.


Can’t code withoutThe best C# & VB.NET refactoring plugin for Visual Studio
Follow jeff_barnes on Twitter

View Jeff Barnes's profile on LinkedIn

 

Shared Items

Disclaimer

Anything you read or see on this site is solely based on my own thoughts.  The material on this site does not necessarily reflect the views of my employer or anyone else.  In other words, I don't speak for anyone other than myself.  So, don't assume I am the official spokesperson for anyone.