Personalizing RSS Feeds with ASP.NET 2.0
By Erich Peterson
Introduction Really Simple Syndication (RSS) is a common XML standard for syndaicating
web content. It is typically used by content-producing sites to offer a machine-readable version of the latest headlines. For example, news sites
like CNN.com and MSNBC.com offer RSS feeds for breaking news; most blog software includes RSS support that syndicates the blogger's most recent
posts. Since its inception, RSS has radically increased in popularity; today it is hard to find a content-producing website that does not
offer at least one RSS feed.
While RSS can be used to provide a single encompassing syndication feed for a website's content, users oftentimes are interested in RSS feeds
that syndicate content catered to their specific interests. They don't necessarily want to see every article, blog post, or news item
a web site offers. Instead, a particular visitor to CNN.com might only be interested in international news, whereas another might only want to
track the latest business-related news headlines. Websites that provide specialized RSS feeds do so by offering different links for RSS feeds on
different topics. In this article, we will look at an example of how to provide dynamic and customized RSS feeds in an ASP.NET 2.0 application.
Read on to learn more!
A Primer on RSS
RSS is an XML-based standard designed to allow web content providers to publish (syndicate) their frequently updated digital content, such as
podcasts or articles, in a standard aggregated format. Commonly, RSS feeds do not contain the entirety of the content. Rather, the RSS feed
usually provides just a brief description of the content, along with its title and a link to the full content.
This article only lightly touches the RSS standard. For a more in-depth look at the standard and usage examples, refer to the
official RSS 2.0 standard.
The following XML content illustrates the markup in a very simple RSS feed:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>ASP .NET 1.x</title>
<link>http://example.com</link>
<description>Everything you ever wanted to know about ASP .NET 1.x.</description>
<copyright>Copyright 2007. All rights reserved.</copyright>
<item>
<title>An Extensive Examination of the DataGrid Web Control: Part 1</title>
<description>A DataGrid control article series that will span several weeks.</description>
<link>http://www.example.com/Articles/default.aspx?articleid=2</link>
</item>
<item>
<title>.Net Data Caching</title>
<description>In simple terms data caching is storing data in memory for quick access.</description>
<link>http://www.example.com/Articles/default.aspx?articleid=3</link>
</item>
</channel>
</rss>
An RSS feed is made up of (at minimum) the following elements:
An <rss> root element with a version attribute (one per document)
Zero or more <channel> element(s), which is a logical grouping of feeds (not unlike a real TV channel)
A <title> element, containing the title of the channel (required).
A <description> element, containing the description of the channel (required).
A <link> element, containing a link back to the channel's main page (required).
A <copyright> element, containing copyright information (optional).
Zero or more <item> element(s) which denote the beginning of a new item within a channel; sometimes an item is known as a "story."
A <title> element, containing the title of the item (optional).
A <description> element, containing a description of the item (optional).
A <link> element, containing a link to the item's full content.
Along with the items listed above, the standard also specifies a number of additional optional elements. Refer to the
RSS 2.0 standard for more information.
To see an example of a "real" RSS feed in action, you need look no further than this website, which uses an RSS feed to share the most
recently published articles. Visit http://aspnet.4guysfromrolla.com/rss/rss.aspx
to see the RSS feed. What you see when visiting an RSS feed through a browser depends on the browser you are using. Modern browsers - IE 7 and
Firefox 2.0 - display RSS feeds in a standardized, rich format. Older browsers may display the RSS feed as raw XML or format the feed based on
a stylesheet specified by the RSS feed. Note that each content item in the 4GuysFromRolla.com RSS feed provides a title, a link to the article, the date and time the article was published,
and the article's introduction. Clicking the title of the article sends you to the full text of the article.
Scott Mitchell shared the code used for the 4Guys RSS feed in
Syndicating Your Web Site's Content with RSS and ASP.NET. 4Guys
provides only a single RSS feed. It could, however, break up this single RSS feed into feeds by category. That is, rather than the master RSS
feed (or in addition to it), Scott could add an RSS feed for ASP.NET 1.x-specific articles, one for ASP.NET 2.0-specific articles, and so forth.
This article looks at how to construct such a system. Specifically, our example website will have four article categories: ASP.NET 1.1, ASP.NET 2.0,
SQL Server 2000, and SQL Server 2005. A visitor can specify the category she wants to subscribe to; the web page will then output the URL
specific to that feed. Visiting that feed will dynamically generate the XML sharing the articles for the specified category.
For more information on RSS, see the RSS Wikipedia entry; use
FeedValidator.org's free tools to validate that your RSS feed is well-formed and correct
according to the official standard.
Building the Database Infrastructure
We need a database to house the categories and content to be syndicated. This database will contain two tables: one for the categories and one
for the articles. These tables' schemas are shown below.
Note: A SQL Server 2005 Express database with the presented schema, along with all the sample code, can be downloaded at the end of
this article.
Creating the Website and Necessary Web Pages
With our database tables constructed and sample data stored within them, we can now dive into the ASP.NET pages and code. We will need to first
create a new web project using Visual Studio (or the free Visual Web Developer).
This web application needs just two web pages:
Default.aspx - lists the categories in a pageable DetailsView, with a link to view the category-specific RSS feed, and
RSS.aspx - accepts a CategoryID value as input through the querystring (like RSS.aspx?category=CategoryID)
and then emits the RSS feed XML for the content for the specified CategoryID.
The following screen shot shows the Default.aspx page when viewed through a browser.
This page was created using two SqlDataSource controls: one to bind and populate a DropDownList with rows contained within the
Categories table and the other to bind and populate a DetailsView with more details about the particular category selected.
The DetailsView includes a HyperLinkField with the label "RSS Feed URL" and a dynamic URL with the format ~/RSS.aspx?category=CategoryID.
The RSS.aspx page serves an RSS feed that contains the content from the specified category. Since an RSS feed is simply XML output,
we do not include any HTML or Web control markup in the .aspx portion of the page. In the .aspx portion you will
only find the @Page directive and the
@OutputCache directive (and no other markup):
The @OutputCache directive instructs the ASP.NET engine to cache the output of this page for 120 seconds, varying the output cache
by the Category querystring parameter. Caching makes sense here because articles are not likely to be created or updated
extremely frequently. In fact, on 4Guys articles appear, on average, once a week. Therefore, the caching duration could feasibly be extended to
several hours. For more on ASP.NET's output caching, see Caching with ASP.NET.
Let's examine the RSS.aspx page's code-behind class. Note that the following namespaces are referenced in using
statements:
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Xml;
The most important of the four namespaces, for our purposes, is System.Xml, which includes the classes we will use for generating
the RSS feed's XML output. The following code is taken from the Page_Load event handler:
// find out if the query string parameter is present
if (Request.QueryString["category"] != null && Request.QueryString["category"] != "")
{
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()))
{
using (SqlCommand cm = new SqlCommand())
{
// get the CategoryId from the query string
int qsCategory = Convert.ToInt32(Request.QueryString["category"]);
// set the conenction and query string
cm.Connection = cn;
cm.CommandText = "SELECT Title, Description FROM Categories WHERE " +
"CategoryId = @CategoryId";
// create parameter for our command and give it a value
SqlParameter parmCategories = new SqlParameter("@CategoryId", SqlDbType.Int);
parmCategories.Value = qsCategory;
// add the parameter to the command object
// and open the connection
cm.Parameters.Add(parmCategories);
cn.Open();
// execute the query and return the results to a SqlDataReader
SqlDataReader dr = cm.ExecuteReader();
if (dr.Read())
{
// clear out the buffer
Response.Clear();
// set response content type
Response.ContentType = "text/xml";
// delcare and instantiate XMLTextWriter object
XmlTextWriter xtw = new XmlTextWriter(Response.OutputStream, Encoding.UTF8);
// write out the XML declaration and version 1.0 info
xtw.WriteStartDocument();
// write out the rss xml element "rss" (required)
xtw.WriteStartElement("rss");
xtw.WriteAttributeString("version", "2.0");
// write out "channel" element (required)
xtw.WriteStartElement("channel");
// write out title, link, and description based on the feed being requested,
// all three elements are required
xtw.WriteElementString("title", dr["Title"].ToString());
xtw.WriteElementString("link", "http://www.example.com/");
xtw.WriteElementString("description", dr["Description"].ToString());
xtw.WriteElementString("copyright", "Copyright " + DateTime.Now.Year.ToString() + ". All rights reserved.");
// close the connection and clear the existing parameters
dr.Close();
cm.Parameters.Clear();
// add parameter and execute query to return article details
SqlParameter parmArticles = new SqlParameter("@CategoryId", SqlDbType.Int);
parmArticles.Value = qsCategory;
cm.Parameters.Add(parmArticles);
dr = cm.ExecuteReader();
// Loop through the content of the database and add them to the RSS feed
while (dr.Read())
{
xtw.WriteStartElement("item");
xtw.WriteElementString("title", dr["Title"].ToString());
xtw.WriteElementString("description", dr["Description"].ToString());
xtw.WriteElementString("link", "http://www.example.com/default.aspx?articleid=" + dr["ArticleId"]);
xtw.WriteEndElement();
}
dr.Close();
I know there's a lot of code above, but it is not that complicated. First, we check to make sure the Category query string parameter
is present. Information about the specified category is retrieved
from the Categories table. Once this information has been retrieved,
an XmlTextWriter object
is used to programmatically create the XML corresponding to the RSS feed.
The XmlTextWriter class contains many useful methods for outputting XML, such as the
WriteStartDocument method,
which outputs the <?xml ?> markup that signifies the start of an XML document.
<?xml version="1.0" encoding="utf-8"?>
There's also the WriteStartElement
method, which will write out the opening tag of an element, given the name of the element. In our case, the first time we call this method
we pass the string "rss". This will result in the opening tag <rss> to be outputted. Furthermore, the
WriteAttributeString method allows us to add an attribute to the current element. This method is used to set the
<rss> element's version attribute value to "2.0".
Finally, the WriteEndElement method is used to close the nearest open element.
Returning to our code's flow of execution, once we have outputed all the required XML elements, we query the database again for specific articles
within the specified category, loop through the results, and output the desired RSS elements (e.g. <item>,
<title>, <description>, and <link>) for each article. If we were to really implement
this in a real-world setting, one would want to probably add another field to the Articles database table named
DateOfPublication (or something similar). With such a field, we would update the database query to return just the ten most recently
published articles:
SELECT TOP 10 ArticleId, Title, Description, DateOfPublication
FROM Articles
WHERE CategoryId = @CategoryId ORDER BY DateOfPublication DESC
We could also include the date published information within each RSS feed item by using the optional <pubDate> element.
Because some browsers such as IE 7 and Firefox 2 have built in RSS readers, if a user followed one of your RSS feed links directly in their
browser, they should see a nice representation of the RSS feed's content—like the one shown in the following screen shot.
Conclusion
Creating personalized RSS feeds are not at all difficult to implement and provide the user with a means to subscribe to RSS feeds focused on
their interests. While this article focused on creating customized RSS feeds for a single, specific category, with a bit more effort you could
update the RSS.aspx page to accept a variable number of Category querystring parameters, allowing users to create
a single RSS feed that is a conglomoration of one or more categories. I invite the interested reader to tackle this problem as an exercise.