When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, June 6, 2007

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!

- continued -

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):

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RSS.aspx.cs" Inherits="_RSS" %>
<%@ OutputCache VaryByParam="category" Duration="120" %>

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();

      // prepare new query
      cm.Connection = cn;
      cm.CommandText = "SELECT ArticleId, Title, Description FROM Articles "
        + "WHERE CategoryId = @CategoryId";

      // 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();

      // Close all tags
      xtw.WriteEndElement();
      xtw.WriteEndElement();
      xtw.WriteEndDocument();
      xtw.Flush();
      xtw.Close();
    }
    else
    {
      Response.Write("Non valid RSS feed URL.");
    }
   }
  }
}
else
{
  Response.Write("Non valid RSS feed URL.");
}

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.

Happy Programming!

  • By Erich Peterson


    Attachments:


  • Download the demo application used in this article


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article