Recently, it occurred to me that one of my websites would probably benefit from an RSS feed. However, I really didn’t understand what RSS feeds were. I understood the basic purpose but really had no clue as to how they worked. With words like “syndication” being tossed around when describing RSS feeds, I had imagined it involved some sort code that continually sent data to some mystical location.
Fortunately, understanding RSS feeds is very easy, and creating your own RSS feed in ASP.NET is a breeze. RSS stands for Really Simple Syndication. It provides a standard for you to make information available to anyone who wants to request your feed. One of my sites is a shareware site and I thought a feed would allow users to stay in contact with my site and make it more likely that they would return. Moreover, an RSS feed allows them to do this without signing up or even giving me their email address.
These days, it’s getting easier for users to use feeds because more and more software is starting to support them. For example, when you enter the URL of a feed into Microsoft Internet Explorer, the information is now formatted specifically for feeds. Microsoft Live Mail also has direct support for feeds. There are also a number of websites that can help you to subscribe to and view RSS feeds.
An RSS feed is simply an XML file on your site that conforms to the RSS specification. Of course, since feeds are meant to be constantly updated, you would normally want to generate this file on-the-fly when it is requested. And, of course, ASP.NET makes this very easy to do.
Listing 1 shows my feed file. This is a normal, every day ASPX file and what you see makes up the entire contents of the file. The first thing to notice is the OutputCache declaration on the second line. When you use OutputCache, requests for this file within the given duration will simply return a copy of the previous results. The duration is in seconds, so if two requests for this file occur within two minutes, the code will not run again for the second request. Instead, ASP.NET will simply return the same data that was returned for the first request. Since the page runs potentially lengthy code and makes a potentially substantial hit on the database, this ensures the site doesn’t get bogged down under heavy traffic.
<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ OutputCache Duration="120" VaryByParam="none" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="SoftCircuits" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.ContentType = "text/xml";
XmlTextWriter writer = new XmlTextWriter(Response.OutputStream,
Encoding.UTF8);
writer.WriteStartDocument();
writer.WriteStartElement("rss");
writer.WriteAttributeString("version", "2.0");
writer.WriteStartElement("channel");
writer.WriteElementString("title", "File Parade's Newest Submissions");
writer.WriteElementString("link", "http://www.fileparade.com");
writer.WriteElementString("description",
"The latest freeware and shareware downloads from File Parade.");
writer.WriteElementString("copyright",
String.Format("Copyright {0} SC Web Group. All rights reserved.", DateTime.Today.Year));
writer.WriteStartElement("image");
writer.WriteElementString("url",
"http://www.fileparade.com/Images/logo88x31.png");
writer.WriteElementString("title",
"File Parade Freeware and Trialware Downloads");
writer.WriteElementString("link",
"http://www.fileparade.com");
writer.WriteEndElement();
using (SqlDataReader reader = DataHelper.ExecProcDataReader("GetRssFeed"))
{
while (reader.Read())
{
writer.WriteStartElement("item");
writer.WriteElementString("title",
EncodeString(String.Format("{0} {1} by {2}",
reader["Title"], reader["Version"],
reader["Company"])));
writer.WriteElementString("description",
EncodeString((string)reader["Description"]));
writer.WriteElementString("link",
String.Format("http://www.fileparade.com/Listing.aspx?id={0}",
reader["ID"]));
writer.WriteElementString("pubDate",
((DateTime)reader["ReleaseDate"]).ToShortDateString());
writer.WriteEndElement();
}
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
writer.Close();
Response.End();
}
protected string EncodeString(string s)
{
s = HttpUtility.HtmlEncode(s);
return s.Replace("\r\n", "<br />\r\n");
}
</script>
Listing 1: RSS Feed
Next are my declarations to import the needed namespaces. Nothing special here—just the declarations needed for database access. Note that this code won’t run for you as listed. It includes my SoftCircuits namespace, which contains some in-house routines for the database. You’ll need to replace this with your own database code. This makes sense since you’ll be returning your own data.
The core of the code is placed in the Page_Load event handler. As you know, this code is called when the page is first requested. The first step is to clear the response of any previously output content. Remember, we are creating an XML file and we don’t want any other content to be returned. Next, we set some headers so that the user agent can see what type of content we are returning.
From here, we go ahead and create an XmlTextWriter and attach it to our output stream, and we can start creating our output. We start with some mandatory RSS tags—these are need to identify our content as an RSS file. Next, we add some mandatory tags that describe our channel. This provides additional, descriptive information about our content. Next, I add some optional tags, which specify a small image and related data.
After that, we can finally start to output our actual data. My code uses an in-house method called DataHelper.ExecProcReader, which calls a stored procedure to obtain my data. You will need to replace this with your own code to return whatever data you are syndicating. My routine simply returns a SqlDataReader and I loop through each row in the data it returned.
Note that I perform some modifications to my text fields before writing them. In my case, this text is submitted from various authors and I don’t want them to include their own HTML markup. So I call HtmlEncode, which causes markup to appear as it was written instead of allowing it to modify the layout, formatting, or creating links. I then insert my own markup by placing <br /> wherever there is a newline. This ensures newlines will appear for the user. I should point out that WriteElementString() will HTML-encode the string being written. This prevents markup from disturbing the XML markup. Note that data will be HTML-decoded when it is read. So you only need to mess with this if you want to tweak the data you are returning.
We then flush the XML writer for good measure, and terminate our response. Again, we are creating an XML file and this last step prevents any other output from accidently being included in the response.
If you’re like me, you may be a little surprised how easy this really is. To allow someone to check your feed, you simply provide them with the URL to this page. Using software that supports feeds, they can have instant access to your data in a convenient format. And, of course, are more likely to return to your site when they need more information.