Syndicating and Consuming RSS 1.0 (RDF) Feeds in ASP.NET 3.5
By Scott Mitchell
Introduction
Websites that produce new content on a regular basis should include a syndication feed, which is a specially formatted XML file that includes a summary of the most recently published items. Virtually all blogs, news sites, and social media sites have a syndication feed, and 4Guys is no exception. The 4GuysFromRolla.com syndication feed contains the most recent articles. Syndication feeds are meant to be consumed by computers. Sites like Technorati parse the syndication feeds from blogs and use that data to determine the topic du jour. Also, syndication feeds are commonly used by websites to display the latest headlines from related sites. For example, an ASP.NET community website could consume the 4GuysFromRolla.com syndication feed to display the latest 4Guys headlines.
Until recently, there was no built-in support for creating or consuming syndication feeds in the .NET Framework. That changed with the release of the .NET Framework version
3.5, which included a new namespace: System.ServiceModel.Syndication
.
This new namespace includes a handful of classes for working with syndication feeds. As aforementioned, syndication feeds are XML files, and for the syndication feed to be
of any use it must conform to one of the popular syndication feed standards. The two most popular syndication feed standards are
RSS 2.0 and Atom 1.0, and these are the standards
supported by the classes in the System.ServiceModel.Syndication
namespace. But there is a third format that, while not as popular as RSS 2.0 or Atom 1.0, is still
used. That standard is RSS 1.0.
The good news is that with a little bit of work we can create a class that works with the RSS 1.0 standard and have this class used by the syndication feed-related classes in the .NET Framework 3.5 can be. This article introduces a free library, skmFeedFormatters, which you can use in an ASP.NET 3.5 application to create and consume RSS 1.0 feeds. (This same concept could be applied to creating and parsing Atom 0.3 feeds, as well.) Read on to learn more!
A Brief History of Syndication Feed Standards
The idea of online syndication feeds was first proposed by Dave Winer back in 1997 as a way for exposing the content of his blog in a machine-readable format. Dave called his standard RSS for Really Simple Syndication. Over the years he continued fine tuning the standard until 2003, at which point the standard was frozen with the release of RSS 2.0. RSS 2.0 is a very popular syndication feed standard in large part because it is very simple and straightforward, making it easy to implement and parse. For example, the 4Guys syndication feed adheres to the RSS 2.0 standard.
Around the same time a group from Netscape set about crafting a syndication standard based on Resource Description Framework (RDF), a standard proposed by the W3C for representing information about resources on the web. To make things as confusing as possible, this new syndication feed standard was named RDF Site Summary, or RSS for short, resulting in two differing standards with the same acronym! Eventually, this work by Netscape (and later O'Reilly) became known as RSS 1.0 and Dave's standard as RSS 2.0, although sometimes the RSS 1.0 standard is referred to as RDF to help remove any ambiguity.
After the RSS 2.0 standard was frozen in 2003, Sam Ruby proposed a new standard to overcome RSS 2.0's shortcomings. This new standard was defined by the community and named Atom. The first major release was Atom 0.3. After some more changes, the final, standardized version was released as Atom 1.0. (Unfortunately, some sites still syndicate content using the Atom 0.3 standard.)
The two most widely used standards are RSS 2.0 and Atom 1.0. However, some sites still use RSS 1.0 or Atom 0.3. For example, the popular tech news and discussion site Slashdot.org syndicates its content using RSS 1.0.
Creating and Consuming Syndication Feeds in ASP.NET 3.5
The .NET Framework version 3.5 introduced a new namespace,
System.ServiceModel.Syndication
, with a number of classes for creating and consuming syndication feeds.
These classes are divided into two categories: classes that model a syndication feed and the items in a feed, and classes that are responsible for transforming the classes
that model syndication feeds into the appropriate XML and vice-a-versa.
- Classes That Model Syndication Feeds and Items
SyndicationFeed
- represents a syndication feed. Has properties likeTitle
,Description
,Links
, andItems
. TheItems
property represents the collection of content items expressed in the feed.SyndicationItem
- represents a specific syndication feed item and includes properties likeTitle
,Summary
,PublishDate
,Authors
, and so on.
- Classes That Transform Syndication Feeds To/From XML
Rss20FeedFormatter
- can take aSyndicationFeed
object and turn it into XML that conforms to the RSS 2.0 specification. Also, can be used to consume a properly-formatted RSS 2.0 feed, turning the XML into aSyndicationFeed
object with its properties set based on the data in the consumed XML.Atom10FeedFormatter
- same as theRss20FeedFormatter
, but uses the Atom 1.0 standard.
A more formal approach, in my opinion, is to create your own feed formatter class. The Rss20FeedFormatter
and Atom10FeedFormatter
classes in the
System.ServiceModel.Syndication
namespace derive from the base class
SyndicationFeedFormatter
. We can create our
own formatter class by extending this base class. For example, we could create an Atom03FeedFormatter
class and use it to turn a
SyndicationFeed
object into conforming XML, or consume an Atom 0.3 XML feed and generate a corresponding SyndicationFeed
object.
The download available for download at the end of this article includes a class named Rss10FeedFormatter
, which can be used to create and consume RSS 1.0 feeds.
The download also includes a demo website showing this class in action. The remainder of this article explores the Rss10FeedFormatter
class.
(You could take the concepts presented in this article to create an Atom03FeedFormatter
class, or a class to work with other, more esoteric feed formats, should
the need arise.)
How Do You Create and Consume Syndication Feeds Using the New Classes in the .NET Framework Version 3.5? |
---|
This article does not walk through using the SyndicationFeed class and the Rss20FeedFormatter and Atom10FeedFormatter classes to
create and consume syndication feeds. It assumes the reader is already familiar with performing these tasks.
For a detailed look at creating and consuming feeds using the classes in the |
A Quick Overview of the RSS 1.0 Standard
Before we get started examining the code for the
Rss10FeedFormatter
class, let's first take a moment to explore the RSS 1.0 standard, which is available online at
http://web.resource.org/rss/1.0/spec. Like an RSS 2.0 feed, an RSS 1.0 feed is designed to express information about recently
published content items. In a nutshell, an RSS 1.0 feed starts with the XML element <RDF>
. Following that, a <channel>
element
describes information about the feed, including the feed's title, description, a link, and so on. The <channel>
element also must contain an
<items>
element that serves as a table of contents of sorts. The feed's items come after the <channel>
element and are each represented
by an <item>
element. The <item>
element has children elements that describe the item's title, link, and description.
RSS 1.0 is more complex than RSS 2.0 in part because RSS 1.0 includes XML namespaces. The root element (<RDF>
) must include two namespaces:
http://www.w3.org/1999/02/22-rdf-syntax-ns#
and http://purl.org/rss/1.0/
, and these must appear in the root element like so:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/">
|
Note that the rdf
namespace prefix must be used with the root element name, as in: <rdf:RDF>
. The rdf
prefix is also used
in other elements in the document.
One feature that makes RSS 2.0 so simple is that there are no attributes, save for the version
attribute in the root <rss>
element. However, in an
RSS 1.0 document there are many elements with attributes. For example, each item must have an rdf:about
attribute that provides a URI that uniquely identifies the
item within the document. (Usually the link to the content item is used for this attribute value.) This rdf:about
attribute is referenced in the
"table of contents" in the <channel>
element.
An example RSS 1.0 feed composed of three content items follows.
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/">
|
Creating a Syndication Feed Formatter Class
The syndication feed formatter classes in the
System.ServiceModel.Syndication
namespace derive from the SyndicationFeedFormatter
and are responsible
for turning a SyndicationFeed
object into corresponding XML and parsing XML and generating a SyndicationFeed
object. The SyndicationFeedFormatter
class has a Feed
property that holds the SyndicationFeed
object being worked on by the formatter. The SyndicationFeedFormatter
class
defines four abstract methods, which are methods that the base class must override:
CanRead(XmlReader)
- returns a Boolean value that indicates whether the formatter can parse the supplied feed.ReadFrom(XmlReader)
- parses the suppliedXmlReader
, reading its contents into theSyndicationFeed
object stored in theFeed
property.WriteTo(XmlWriter)
- writes the information stored by theSyndicationFeed
object in theFeed
property to the passed-inXmlWriter
object.CreateFeedInstance()
- creates and returns a newSyndicationFeed
object.
ReadFrom
method is used to turn XML into a SyndicationFeed
object, whereas the WriteTo
method transforms a SyndicationFeed
object into XML.
The SyndicationFeedFormatter
class also defines an abstract string property named Version
, which indicates the syndication feed standard version being used.
The Rss10FeedFormatter
returns the value "Rss20", for example.
To create a syndication feed formatter class, start by creating a class that derives from SyndicationFeedFormatter
. The following code shows the shell of the
Rss10FeedFormatter
class In addition to the abstract methods and property, this shell also includes two constructors and two read-only properties. The
first constructor is the default constructor, while the second one accepts a SyndicationFeed
object as an input parameter and passes it to the base class's
constructor. This base constructor called by this latter constructor assigns the supplied SyndicationFeed
object to the base class's Feed
property.
The two read-only properties simply define the namespaces used by the RSS 1.0 specification.
public class Rss10FeedFormatter : SyndicationFeedFormatter
|
Consuming RSS 1.0 XML
The
SyndicationFeedFormatter
base class defines two abstract methods for reading an XML document: CanRead(XmlReader)
and ReadFrom(XmlReader)
.
The CanRead(XmlReader)
method returns a Boolean value indicating whether the feed can be read. We can only read an RSS 1.0 feed if it starts with the
expected root element, namely <RDF>
with the namespace http://www.w3.org/1999/02/22-rdf-syntax-ns#
. This is precisely what the CanRead
method checks for:
public class Rss10FeedFormatter : SyndicationFeedFormatter
|
The real work occurs in the ReadFrom(XmlReader)
method, which is responsible for parsing through the XML documents and creating a corresponding SyndicationFeed
object populated with SyndicationItem
objects for each item defined in the feed. This code consumes the bulk of the Rss10FeedFormatter
class. An
abbreviated version is shown below. Specifically, the code illustrated here reads in the channel
elements and assigns the values in a SyndicationFeed
object named result
.
public class Rss10FeedFormatter : SyndicationFeedFormatter
|
The above code reads to the <channel>
element and then loops through the children elements. If it finds a <title>
element it extracts
the value and assigns it to the SyndicationFeed
object's Title
property. Likewise, if it finds a <link>
element it extracts its value,
creates a new SyndicationLink
object, and adds is to the SyndicationFeed
object's Links
collection. Any element other than
<title>
, <link>
, or <description>
is skipped.
Note that the formatter does not do any validation on the RSS 1.0 feed it's reading. For example, according to the specification the <channel>
element's
<title>
, <link>
, and <description>
elements are required. However, no error is raised if these elements are missing.
By the time the ReadFrom
method completes, the Feed
property has had its relevant properties assigned to the corresponding values from the XML.
The demo website included in the download at the end of this article includes a page to test consuming an RSS 1.0 feed (~/ConsumeRSS10.aspx
). Here, you can enter
the URL to an RSS 1.0 feed. The specified feed can be parsed using the following three lines of code:
// Read in the RSS 1.0 feed from the specified URL
|
After the last line of code executes, the formatter.Feed
property contains the SyndicationFeed
information. You can work with this data programmatically
or bind it to a data Web control, such as a GridView or ListView. (The ~/ConsumeRSS10.aspx
page binds the results to a ListView.) The following screen shot shows
the ~/ConsumeRSS10.aspx
page in action when parsing the Slashdot RSS 1.0 feed.

Syndicating RSS 1.0 XML
The
SyndicationFeedFormatter
class also includes facilities for generating the XML for an existing SyndicationFeed
object, and does so through its
WriteTo(XmlWriter)
method, which outputs the corresponding XML to the passed-in XmlWriter
instance. This code for writing the XML is a bit lengthy,
as you might imagine. For the sake of brevity, let's just look at the code that creates the starting <RDF>
element, the <channel>
element and
its first few children elements.
The following code writes out the root node with the required namespace definitions.
public class Rss10FeedFormatter : SyndicationFeedFormatter
|
Next, we need to write out the <channel>
element and its children. I've omitted some of the code that determines the value to use for the
<channel>
element's rdf:about
attribute, as well as the <link>
element, for brevity.
...
Continued from above ...
|
Unlike the code that consumes a feed, the code that syndicates it performs various checks to ensure that a valid feed is generated. For example, if the
SyndicationFeed
object being syndicated doesn't include a value for its Title
property then the feed is invalid because RSS 1.0 feeds
must include a <title>
child element within the <channel>
element.
The demo website includes the ability to generate a syndication feed using either:
- Atom 1.0
- RSS 2.0
- RSS 1.0
Feed.aspx
page passing in the type through the querystring (either Rss10
, Rss20
, or Atom
).
For example, to generate the feed in conformance with the RSS 1.0 standard you would visit: Feed.aspx?Type=Rss10
. The code in the Feed.aspx
page's code-behind
class builds the SyndicationFeed
object and its Items
based on data from the pubs
database. It then uses the appropriate
formatter class based on the Type
querystring parameter value. In the following code, myFeed
is a populated SyndicationFeed
object.
The feed formatter class used outputs the XML to the Response.OutputStream
stream, which returns the markup to the requesting user agent.
XmlWriter feedWriter = XmlWriter.Create(Response.OutputStream);
|
Conclusion
The syndication feed-related classes in the .NET Framework version 3.5 make it a snap to create and consume RSS 2.0 and Atom 1.0 syndication feeds. If you need to create or consume feeds that use an alternative standard you can create a custom feed formatter class. This article showed how to create a formatter class for RSS 1.0 feeds. You are welcome to download and use this code in your web applications.
Happy Programming!
Attachments:
Further Reading