Published: 23 Feb 2009
By: Scott Mitchell
Download Sample Code

Scott Mitchell explains how to take advantage of syndication feeds.

Contents [hide]

Introduction

Virtually every website that produces new content on a regular or semi-regular basis provides a syndication feed. Syndication feeds were first used with blogs as a means for sharing the most recent entries, but soon spread to news sites. For instance, CNN.com has a feed that syndicates their breaking news headlines and one that syndicates the latest sports news, along with many others. Today, syndication feeds are used to share all sort of content: Flickr syndicates each user's most recently uploaded images; each project in CodePlex (Microsoft's open-source project hosting website) has a feed that syndicates the latest releases; and Twitter syndicates each user's most recent tweets.

A syndication feed contains information about the most recently published items using a standardized XML format. Because the syndication feed conforms to a known XML standard, its data can be parsed by any computer program that knows how to work with the syndication standard. For example, you can subscribe to various syndication feeds using Microsoft Outlook's RSS Feeds folder. Adding a feed to this folder displays the syndication feed's content items; furthermore, Outlook automatically checks the syndication feed every so often to determine if there is new content. Syndication feeds are also routinely consumed by other websites. The ASP.NET Forums includes a feed that syndicates the 25 most recent posts. This feed is consumed and displayed in the ASP.NET Developer Center on Microsoft's MSDN website. Similarly, you could consume the Twitter feed that syndicates your latest tweets and display them on your blog.

Creating and consuming syndication feeds from an ASP.NET application is a walk in the park thanks to the classes in the System.ServiceModel.Syndication namespace. This article shows how to use these classes to create a syndication feed for your website as well as how to use them to consume and display syndication feeds from other websites. These techniques are demonstrated in a demo web application, which is a website for a fictional book company, Nile.com. This demo site includes a feed that syndicates the most recently published book titles; it also consumes and displays the headlines syndicated by RareBookNews.com.

A Bit of History

Before we delve into the meat of this article it would be worthwhile to spend a moment reviewing the history of syndication standards and the support for working with syndication feeds in .NET. The first syndication feed standard was proposed by Dave Winer in 1997. Over the years this initial syndication standard morphed into what is today known as RSS. The RSS specification was frozen in 2003 with the release of RSS 2.0.

Shortly after RSS 2.0 was released, Sam Ruby proposed a new syndication format to address the shortcomings of the now frozen RSS standard. Over the next several months Ruby and others created a new syndication format named Atom. The Atom 1.0 standard was ratified by the Internet Engineering Task Force (IETF) in 2007.

The .NET Framework did not provide any built-in functionality for creating or consuming syndication feeds until version 3.5 with the introduction of the System.ServiceModel.Syndication namespace. The most germane class in this namespace is SyndicationFeed. As you can probably guess from its name, this class represents a syndication feed. It has properties like Title, Description, Links, and Copyright, which provide details about the feed. The content items that make up the feed are specified via the Items property, which is a collection of SyndicationItem objects. The SyndicationFeed class also has a static Load method that parses and loads the information from a specified RSS 2.0 or Atom 1.0 syndication feed.

In addition to the SyndicationFeed and SyndicationItem classes, the System.ServiceModel.Syndication namespace also includes two formatter classes, Atom10FeedFormatter and Rss20FeedFormatter. These classes take a SyndicationFeed object and generate the corresponding XML content that conforms to either the Atom 1.0 or RSS 2.0 specificiations.

Note:

In 2000 a group at O'Reilly created their own syndication format standard that differed from the then current RSS 0.91 standard. Unfortunately, this group named their new syndication format RSS 1.0, even though it was not related to RSS 0.91 (which later became RSS 2.0). Therefore, RSS 2.0 and RSS 1.0 are significantly different from one another. Similarly, a number of sites started using Atom before it was standardized by the IETF, most notably Google. As a result, many of Google's Atom syndication feeds still use Atom 0.3 instead of Atom 1.0.

The SyndicationFeed class can only parse feeds that conform to the RSS 2.0 or Atom 1.0 standards. The good news is that the vast majority of the syndication feeds on the web use one of these two standards. And if you need to parse an RSS 1.0 or Atom 0.3 feed you can translate the XML content into Atom 1.0-compliant XML on the fly before loading it into a SyndicationFeed object. For more information on this technique check out Daniel Cazzulino's blog entry on upgrading Atom 0.3 feeds on the fly.

Creating a Syndication Feed For Your Website

Every website that routinely publishes any kind of content should offer a syndication feed. A syndication feed can be a static XML file that gets created automatically whenever new content is published or it can be a dynamic web page that gets the latest published items and emits the appropriate XML markup. The demo website uses the latter method.

Creating a syndication feed from a dynamic web page involves three steps:

  1. Create a page that generates the feed's content.
  2. Get the most recently published items to appear in the syndication feed.
  3. Generate and output the feed's XML markup.

Let's walk through each of these steps.

Creating the Syndication Feed Web Page

The syndication feed web page's output is generated programmatically using the classes in the System.ServiceModel.Syndication namespace. Therefore, when creating this page make sure you do not associate it with a master page; once the page has been created remove all of the content from the.aspx page except for the @Page directive.

The demo website's syndication feed is implemented by the Feed.aspx page. The contents of the .aspx page follow:

Note that in addition to the @Page directive the .aspx portion also includes an @OutputCache directive. The @OutputCache directive caches the content returned by the syndication feed for the specified Duration - in this case, 60 seconds. In other words, when the first user requests the syndication feed the XML output is cached. For the next 60 seconds, requests for the syndication feed return the XML output stored in the cache rather than having it regenerated by the page. The VaryByParam attribute indicates that the output caching engine should maintain a separate cached output for each unique Type value. As we'll see shortly, the Feed.aspx page accepts an optional Type querystring parameter that indicates the syndication format used. Visiting Feed.aspx or Feed.aspx?Type=Atom returns the syndicated content in accordance with the Atom 1.0 standard, whereas visiting Feed.aspx?Type=RSS returns XML that is in accordance with the RSS 2.0 standard.

For more information on output caching check out my article, Output Caching in ASP.NET.

Retrieving the Most Recently Published Items

The demo application's underlying author and title information comes from the pubs database, which you'll find in the App_Data folder, and uses LINQ to SQL as the Data Access Layer. The LINQ to SQL classes are defined in the Pubs.dbml file, which you'll find in the App_Code folder.

The Page_Load event handler in Feed.aspx starts with the following statement, which retrieves the books from the Titles table ordered in reverse chronological order of their publish date.

That was easy!

Generating the Syndication Feed's XML Output

The last step is to turn the most recently published items into the appropriate syndication feed XML markup. After the dataItems variable is created (see the above code snippet) the Feed.aspx page defines a constant that specifies the maximum number of recently published items to include in the feed and then determines whether to generate an RSS 2.0 or Atom 1.0 syndication feed. The value of the Type querystring parameter dictates which syndication standard is used.

Regardless of what syndication standard you use, the code for constructing the SyndicationFeed object is (mostly) identical. There are a few edge cases that we'll address momentarily. However, the final lines of code that render the SyndicationFeed object into the appropriate XML markup differ based on the syndication standard. Furthermore, the syndication feed should send back a different Content-Type header depending on the syndication format: application/atom+xml for Atom 1.0 feeds and application/rss+xml for RSS 2.0 feeds.

We are now ready to create the SyndicationFeed object and set its properties. As you can see, there are a number of properties associated with the syndication feed, such as: Title, Description, Links, Copyright, and Language, among others.

There is one method used in the above code snippet that is not part of the .NET Framework, and that's GetFullyQualifiedUrl (it is defined further down in the code-behind class). This method accepts a relative URL like ~/Default.aspx and returns the fully qualified URL, like http://www.example.com/Default.aspx.

The next step is to define the syndication feed's items. This is done by creating a List of SyndicationItem objects that contains a SyndicationItem instance for each item to appear in the feed. Once this List has been constructed it can be assigned to the SyndicationFeed object's Items property.

The foreach loop uses the Take method to iterate through only the first maxItemsInFeed number of books in the dataItems collection. In each iteration a SyndicationItem object is created, its properties are set, and the object is added to feedItems, the List of SyndicationItems created immediately before the start of the loop. Note that the Links collection for each SyndicationItems object contains a link to the Titles.aspx page. Typically each content item has a unique URL, such as http://www.example.com/ShowBook.aspx?ID=34, or http://www.example.com/titles/Life_Without_Fear, and those unique URLs would be what you would link to. However, I did not add such a unique page for each book for this demo and therefore decided to have all content items link to the same URL.

There are two checks I added here to ensure that the information added to the feed conforms the the syndication specification being used. At the top of the loop you can see that I bypass adding the current book to the feed's collection of SyndicationItems if there are no authors for the book. This is because the Atom 1.0 specification requires author information with each item. I could have alternatively added a "dummy" author value for such books, with a name and e-mail address of "Unknown" and "unknown@example.com", for example. (No such check is needed when generating an RSS 2.0 feed as the author information is optional in the RSS 2.0 spec.) The second check is at the end of the inner foreach loop, which adds the author information to the current SyndicationItem object. Because the RSS 2.0 specification allows no more than one author we must break out of this loop after the first iteration to ensure that multiple authors are not added.

The final step is to generate the XML markup for the syndication feed and output it to the Response stream. This is handled via an XmlWriter object and either the Atom10FeedFormatter or Rss20FeedFormatter class, depending on whether you want to generate an Atom 1.0 or RSS 2.0 feed.

The XmlWriter object feedWriter sends its output to the Response object's OutputStream. Next, either an Atom10FeedFormatter or Rss20FeedFormatter class is instantiated and its WriteTo method is called, which emits the rendered markup to feedWriter, which outputs it to the client.

That's it! We now have a fully functional syndication feed that can emit either RSS 2.0 or Atom 1.0 XML. For example, visting Feed.aspx?Type=RSS returns the following content:

Consuming a Syndication Feed

In addition to creating and rendering syndication feeds, the SyndicationFeed class can also be populated from an existing syndication feed. With a few lines of code you can build a SyndicationFeed object from an RSS 2.0 or Atom 1.0 feed from another site and then display it in a web page. The Default.aspx page in the demo application provides such functionality, pulling the recent headlines from the RareBookNews.com syndication feed, http://www.rarebooknews.com/index.xml. To load the contents of a syndication feed use the SyndicationFeed class's Load method, passing in an XmlReader instance. Once the SyndicationFeed has been loaded you can bind its Items collection to a data Web control.

The Default.aspx page includes a ListView control named BookNewsList and the following code in the Page_Load event handler:

As you can see, the SyndicationFeed object's Items collection is cached for one hour. It's good netiquette to cache the syndication feed rather than re-requesting it every single time someone visits this page. It's also important to load the SyndicationFeed object in a try...catch block so that you can gracefully recover if the RareBookNews.com site is down.

The BookNewsList ListView's ItemTemplate emits the HTML returned by the DisplayFeedItem method, which is defined in the Default.aspx page's code-behind class. This method takes in a SyndicationItem object and generates the HTML for display. Specifically, it creates a hyperlink that points to the content items URL and displays the title as text. It also shows the item's published date and description.

Figure 1 shows the Default.aspx page when viewed through a browser. The text circled in red were the latest news headlines from RareBookNews.com at the time of writing.

Figure 1: The RareBookNews.com Headlines Are Displayed In Default.aspx

The 

RareBookNews.com Headlines Are Displayed In Default.aspx

Conclusion

Syndication has quickly grown from a technology that was strictly the domain of blogs to one that is embraced by all sorts of websites that routinely publish content. Creating RSS 2.0 or Atom 1.0 syndication feeds, or consuming them, can be accomplished using the classes in the System.ServiceModel.Syndication namespace. Use the SyndicationFeed and SyndicationItem classes for modeling syndication feeds and their items and the Atom10FeedFormatter and Rss20FeedFormatter classes for rendering a SyndicationFeed object into the appropriate XML markup. Be sure to download the demo application. It shows how to create an ASP.NET page that emits either an RSS 2.0 or Atom 1.0 syndication feed, as well as how to consume and display another site's syndication feed.

Happy Programming!

References

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Scott Mitchell

Scott Mitchell, author of eight ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott works as an independent consultant, trainer, ...

This author has published 16 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
jQuery Mobile ListView
In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
Exception Handling and .Net (A practical approach)
Error Handling has always been crucial for an application in a number of ways. It may affect the exe...
JQuery Mobile Widgets Overview
An overview of widgets in jQuery Mobile.
Book Review: SignalR: Real-time Application Development
A book review of SignalR by Simone.

You might also be interested in the following related blog posts


Announcing Microsoft Ajax Library (Preview 6) and the Microsoft Ajax Minifier read more
SOLUTION: JSLint.VS Add-In Always Reports "No Errors" Even For Invalid JavaScript Files read more
Accessing Images On Flickr From An ASP.NET Website Using The Flickr.Net Library read more
Mixing Silverlight and MS ASP.NET AJAX 3.5 in the same web application. read more
Code Review Singleton Pattern Issues read more
Upcoming Talk: Content Syndication With ASP.NET 3.5 (San Diego ASP.NET SIG) read more
Improved type safety when dealing with generic types, generic methods and reflection read more
Silverlight Twitter Client with authentication read more
ASP.NET Membership Tip: Requiring New Users To Change Their Password When Logging On For The First Time read more
Issue 45 - Markit Modules Slideshow and PageEar, DNN Stuff's Module Rotator, Monitter4DNN and Open Web Studio Tutorials read more
Top
 
 
 

Discussion


Subject Author Date
placeholder Is individual element querying supported? abhilashca 6/6/2009 6:43 AM
RE: Is individual element querying supported? Sonu Kapoor 6/8/2009 8:08 AM
placeholder Duplicate feed items in the feed reader (Google) Rahul M 7/12/2009 10:25 PM
vb.net Andrew Hancock 8/28/2009 3:13 PM
placeholder RE: vb.net Scott Mitchell 8/28/2009 3:56 PM
RE: RE: vb.net Andrew Hancock 8/28/2009 4:16 PM
placeholder Limiting the feed items Keith Sheehan 10/20/2009 12:22 PM
RE: Limiting the feed items Scott Mitchell 10/20/2009 12:38 PM
placeholder RE: RE: Limiting the feed items Keith Sheehan 10/20/2009 1:16 PM
Duplicate feed items Greg Farquhar 11/29/2009 10:50 PM
placeholder RE: Duplicate feed items Sonu Kapoor 11/30/2009 8:16 AM
RE: RE: Duplicate feed items Greg Farquhar 12/1/2009 12:56 AM
placeholder RE: RE: RE: Duplicate feed items Sonu Kapoor 12/1/2009 8:05 AM
One line stopping me! (I think) - thanks for the article Janet Barnett 3/23/2011 2:52 PM
placeholder Fix for duplicates Dave Gable 9/19/2012 8:42 PM
Fix For Duplicate Items Dave Gable 9/20/2012 11:53 AM
placeholder Possibly needless optimization Kent Sharkey 2/23/2009 12:39 AM
RE: Possibly needless optimization Scott Mitchell 2/24/2009 3:19 PM
placeholder Syndicating RSS 1.0 Flalar Flalar 2/25/2009 5:37 PM
RE: Syndicating RSS 1.0 Scott Mitchell 2/25/2009 5:48 PM
placeholder RE: RE: Syndicating RSS 1.0 Flalar Flalar 2/26/2009 3:12 AM
RE: RE: RE: Syndicating RSS 1.0 Scott Mitchell 2/26/2009 6:47 PM
placeholder RE: RE: RE: Syndicating RSS 1.0 Scott Mitchell 3/4/2009 3:32 PM
Great Article Barbara Lee 3/2/2009 11:53 PM
placeholder HELP PLEASE!!! Barbara Lee 3/21/2009 1:17 AM
RE: HELP PLEASE!!! Scott Mitchell 3/21/2009 12:06 PM
placeholder RE: RE: HELP PLEASE!!! Barbara Lee 3/21/2009 3:28 PM
RE: RE: RE: HELP PLEASE!!! Scott Mitchell 3/21/2009 5:39 PM
placeholder Help please Ian Cross 4/10/2009 1:50 PM
RE: Help please Scott Mitchell 4/10/2009 6:14 PM

Please login to rate or to leave a comment.