A Simple RSS Feed
| |
The article describes a control that fetches an RSS feed from a site of interest and organizes that content for display on a web page. |
|
Peter Bernhardt
Difficulty: Easy
Time Required: 1-3 hours
Cost: Free
Hardware:
|
Quite a few years ago, I came to the practical conclusion that I don't know everything there is to know about the world. Sure, it's presumptuous to even start from a place that requires such a conclusion. But such arrogance is a failing of youth, and I know better now. In fact, this reality is only magnified in the Internet age, as I find it virtually impossible to keep up-to-date with the non-stop flow of information, ideas, and opinions available on the web. Even within my modest scope of interests, I have a hard time staying current with the latest developments in Visual Basic, Visual C# and the .NET Framework.
So, over the course of my next few entries I'm going to explore different approaches to using something with which you're likely already familiar: RSS (a/k/a Really Simple Syndication) —a technology that greatly eases the burden of grappling with information overload.
As a quick primer, Wikpedia describes RSS as "short descriptions of web content together with links to the full versions of the content. This information is delivered as an XML file called an RSS feed, webfeed, RSS stream, or RSS channel. In addition to facilitating syndication, RSS allows a website's frequent readers to track updates on the site using a news aggregator." (For the full entry, see RSS on Wikpedia).
To get started, we'll look at a simple RSS feed reader you can build using Visual Web Developer 2005 Express Edition. I'm going to build a control that fetches an RSS feed from a site of interest and organizes that content for display on a web page. Of course, you could also build an RSS feed reader as a Windows application, or take advantage of any one of a number of free RSS client applications available (e.g., RSS Reader or SharpReader) if your aim is to aggregate content for your own personal consumption. Using syndicated content in a Web application has a different purpose, however, as it allows you to extend the content you create yourself and enrich the user experience of visitors to your site.
Before getting into the code, let's first take a look at a snippet of a typical RSS 2.0 file. In this example, the syndication provider is Microsoft's MSDN Web site, and I'm using the feed devoted to Visual Basic content.
<rss
xmlns:msdn="http://msdn.microsoft.com/aboutmsdn/rss/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:msdndomain="http://msdn.microsoft.com/aboutmsdn/rss/domains"
version="2.0">
<channel>
<title>MSDN: Visual Basic</title>
<link>http://msdn.microsoft.com/vbasic/</link>
<description>Recently Published Visual Basic Content</description>
<language>en-us</language>
<pubDate>Thu, 30 Jun 2005 13:01:02 GMT</pubDate>
<lastBuildDate>Thu, 30 Jun 2005 13:01:02 GMT</lastBuildDate>
<generator>MSDN RSS Service 1.1.0.0</generator>
<ttl>1440</ttl>
<item>
<title>June CTP of Visual Studio 2005 Available to MSDN Subscribers</title>
<description>The latest Community Technical Preview of Visual Studio 2005 is now
available for download to MSDN subscribers.</description>
<link>http://msdn.microsoft.com/subscriptions/</link>
<category domain="msdndomain:ContentType">Announcement</category>
<category domain="msdndomain:Subject">.NET development</category>
<msdn:headlineImage>
http://msdn.microsoft.com/msdn-online/shared/graphics/icons/article.gif
</msdn:headlineImage>
<msdn:contentType>Announcement</msdn:contentType>
<msdn:simpleDate>Jun 27</msdn:simpleDate>
<guid isPermaLink="false">Titan_1106</guid>
<pubDate>Tue, 28 Jun 2005 02:00:13 GMT</pubDate>
</item>
<!-- more items follow -->
</channel>
</rss>
A typical feed file is loaded with information, some of which is not included uniformly by all syndication providers (MSDN's headline image, for example, is not standard). At the top of the XML structure is a single <channel> node that includes a title and description you can use to introduce the list of content items. The <channel> node contains many child <item> nodes representing each article of content (including the title of the article, a description, publication date and the link to the full article).
After creating a new Web Site in Visual Web Developer 2005 Express Edition, I added a Web User Control that I'll use to display this information.
(click image to zoom)
One of the features of ASP.NET 2.0 is that it supports both the code-behind model familiar to Visual Studio 2003 developers, and (something new) in-line code which allows you to write all your code within <script> tags in the .aspx or .ascx files. While using the in-line code approach doesn't make any difference in how the ASP.NET pages perform, I prefer the code-behind model and will use it throughout this example. You'll also notice that I'm using Visual Basic to write the code for this application.
Working in the designer, I added a Repeater control to the control. The Repeater is a data-bound control for displaying data using a custom layout. This is ideal for showing a list of content items from an RSS feed. As shown below, you can use the smart tag menu associated with the control to set the data source for the control at design. However, for this application I'll be setting the data source at runtime using the RSS feed.
(click image to zoom)
Switching to the code-behind file for the .ascx file (RSSList.ascx.vb), I added Imports statements for the namespaces containing the classes necessary to acquire the RSS feed and store it to a local resource that will bind to the Repeater.
Visual C#
using System.Data;
using System.Net;
Visual Basic
Imports System.Net
Imports System.Data
In addition to using the event handler for the control's Page Load event, I also added a private helper function called RefreshFeed. This gets the RSS data and returns it as a DataSet to the Page Load event handler. In the RefreshFeed function, the first line of code creates an instance of an HttpWebRequest object using the shared Create function of the WebRequest class.
Visual C#
HttpWebRequest rssFeed = (HttpWebRequest)WebRequest.Create(
"http://msdn.microsoft.com/vbasic/rss.xml");
Visual Basic
Dim rssFeed As HttpWebRequest =_
DirectCast(WebRequest.Create("http://msdn.microsoft.com/vbasic/rss.xml"),_
HttpWebRequest)
As an input argument to the Create function, the code passes the target URL of the RSS feed. The function returns an HttpWebRequest object, which is a special type of WebRequest object that supports additional properties and methods for interacting with servers using HTTP. In this case, my needs are very simple for HttpWebRequest; the code first gets the response from the server (GetResponse) and then, because the response is in XML format, the response stream (GetResponseStream) can be loaded directly into a DataSet using the ReadXml method overload that accepts a Stream as an input argument.
Visual C#
DataSet rssData = new DataSet();
rssData.ReadXml(rssFeed.GetResponse().GetResponseStream());
Visual Basic
Dim rssData As DataSet = New DataSet()
rssData.ReadXml(rssFeed.GetResponse().GetResponseStream())
The ReadXml method automatically infers the schema for the XML data. That means the <channel> and <items> nodes of the source XML data are represented in the DataSet as separate DataTables. In the Page Load event handler, after calling the RefereshFeed method to return a DataSet containing the RSS feed data, the code access the channel and items data in different ways. The second DataTable in the DataSet contains the channel information. To display the feed title and description, the code copies the first and only row from the DataTable into an Object array using the ItemArray property of the Row. Then, because I want to be sure I locate the correct data column, the code assigns the ordinal position of the title and description columns, respectively, to local variables of type Integer. Using these values, the code calls the GetValue method of the Object array to store the value associated with each column to the Friend field defined for the class (I'll use these values in the Repeater control).
Visual C#
object[] channelItems = rssData.Tables[1].Rows[0].ItemArray;
int titleColumn = rssData.Tables[1].Columns["title"].Ordinal;
int descriptionColumn = rssData.Tables[1].Columns["description"].Ordinal;
Title = channelItems.GetValue(titleColumn).ToString();
Description = channelItems.GetValue(descriptionColumn).ToString();
Visual Basic
Dim channelItems As Object() = rssData.Tables(1).Rows(0).ItemArray
Dim titleColumn As Integer = rssData.Tables(1).Columns("title").Ordinal
Dim descriptionColumn As Integer =
rssData.Tables(1).Columns("description").Ordinal
Title = channelItems.GetValue(titleColumn).ToString()
Description = channelItems.GetValue(descriptionColumn).ToString()
Next, the code sets the DataSource property of the Repeater control to the DataTable in the DataSet holding the item content from the RSS feed. Finally, the code calls the DatBind method of the Repeater to bind the data source to the control.
Visual C#
Repeater1.DataSource = rssData.Tables(2)
Repeater1.DataBind()
Visual Basic
Repeater1.DataSource = rssData.Tables(2)
Repeater1.DataBind()
In the source view of the RssFeed.ascx control, I added templates for the Repeater control to display the data. In the <HeaderTemplate> the code begins a table with a header element that displays the channel title and description.
<HeaderTemplate>
<table border=0
style="width: 240px; font-size: x-small; color: black; font-family: Verdana;">
<thead>
<tr style="font-weight: bold;">
<td><%#Me.Title%></td>
</tr>
<tr style="font-style: italic;">
<td><%#Me.Description%></td>
</tr>
</thead>
</HeaderTemplate>
Similarly, in the <ItemTemplate> the code displays the title of a content item with its associated link, as well as the description of the item.
<ItemTemplate>
<tr bgcolor="LightBlue">
<td>
<a target="article" style="text-decoration: none; color: black;"
href=&lt;%# DataBinder.Eval(Container.DataItem, "link") %&gt;>
<%# DataBinder.Eval(Container.DataItem, "title") %> </a>
</td>
</tr>
<tr bgcolor="Ivory">
<td style="color: CornFlowerBlue;">
<%# DataBinder.Eval(Container.DataItem, "description") %>
</td>
</tr>
</ItemTemplate>
As a final and very necessary step, I added an OutputCache directive to at the top of the .ascx page to cache the output of the control for one hour.
<%@ OutputCache Duration="3600" VaryByParam="None" %>
This will prevent executing the
RefreshFeed function every time a user access a page containing the control. If I didn't do this, and my site got heavy use, this would result in a lot of traffic between my Web server and the syndication provider. If you run the application, the syndicated content displays as shown below.
(click image to zoom)
In future articles I'll dig deeper into the possibilities for using syndicated RSS feeds in a Web application. Until then, I encourage you to download the code and try it out for yourself.