Creating an ASP.NET RSS Blog Roller with C#

We needed an RSS blog roller for http://www.interfacett.com so we could show employee blogs from various sites.  While there are several out there for .NET we wanted something that we could build on and customize so Spike Xavier and I put together a quick class named RssBlogRoller that would read an array of blog URLs, grab a specific number of items and then sort them based upon the <pubDate> element.  It was a fun little exercise that will be useful in classes as well since it demonstrates generics, XmlReaders (and sub readers) and the ASP.NET ObjectDataSource.

The code for the RssBlogRoller is shown below.  I've refactored it several times now and while it's not perfect, it gets the job done. RssBlogRoller has a method named GetRssItems that returns an array of RssItem objects (also shown below).

using System;
using 
System.Web.Configuration;
using 
System.Xml;
using 
System.IO;
using 
System.Collections.Generic;
using 
System.Web;

namespace 
InterfaceTT {

    
public class RSSBlogRoller {

        
public static RSSItem[] GetRssItems(string rssURLs, 
            
int numberToShow)
        {
            
//Try to grab URLs from web.config
            
if (rssURLs == null) rssURLs 
                
WebConfigurationManager.AppSettings["BlogUrls"];
            if 
(String.IsNullOrEmpty(rssURLs))
            {
                HttpContext.Current.Trace.Warn(
"GetRssItems"
                
"rssURLs is empty.  No blogs to parse were found.");
                return null;
            
}

            
//Get each person's blog URL
            
string[] rssUrlsArray rssURLs.Split(new char[] { ';' });
            
//Check if we have any URLs to retrieve
            
if (rssUrlsArray == null || rssUrlsArray.Length == 0)
            {
                HttpContext.Current.Trace.Warn(
"GetRssItems"
                
"rssURLs is empty.  No blogs to parse were found.");
                return null;
            
}
            
            
//Create dictionary to store each person's blog entries
            //Key is blog URL, value is all the person's entries
            
Dictionary<string, List<RSSItem>> namesFeeds 
                new 
Dictionary<string, List<RSSItem>>();
            foreach 
(string url in rssUrlsArray)
            {
                
if (url.Length > 0)
                {
                    List<RSSItem> blogItems 
= new List<RSSItem>();
                    
RSSItem currItem = null;
                    
XmlReader reader = null;
                    try
                    
{
                        reader 
XmlReader.Create(url);
                        while 
(reader.Read())
                        {
                            
//Exit read operation if we've 
                            //found all we need
                            
if (blogItems.Count > numberToShow) break;
                            if 
(reader.NodeType == XmlNodeType.Element
                                && reader.Name.ToLower() 
== "item")
                            {
                                
//Create a sub XmlReader
                                
currItem ReadRSSItem(reader.ReadSubtree());
                            
}
                            
//After each item end tag create HTML output
                            
if (reader.NodeType == XmlNodeType.EndElement 
                                && reader.Name.ToLower() 
== "item")
                            {
                                
if (currItem != null
                                    blogItems.Add(currItem)
;
                            
}
                        }
                    }
                    
catch (Exception exp)
                    {
                        HttpContext.Current.Trace.Warn(
"GetRssItems"
                            
"Error in reading RSS feed: " + exp.Message);
                    
}
                    
finally
                    
{
                        
if (reader != null) reader.Close();
                    
}
                    
if (blogItems.Count > 0)
                    {
                        namesFeeds.Add(url, blogItems)
;
                    
}                
                }
            } 
//End For

            
RSSItem[] newItems GetRSSItems(namesFeeds, numberToShow);
            
//Will sort by pubDate...implements IComparable<T>
            
Array.Sort(newItems)
            return 
newItems;
        
}

        
private static RSSItem ReadRSSItem(XmlReader subReader)
        {
            
string title = null;
            string 
link = null;
            string 
desc = null;
            
DateTime? pubDate = null; //Nullable<DateTime>
            
string authorName = null;
            
subReader.MoveToContent();
            while 
(subReader.Read())
            {
                
switch (subReader.Name.ToLower())
                {
                    
case "title":
                        title 
subReader.ReadString();
                        break;
                    case 
"link":
                        link 
subReader.ReadString();
                        break;
                    case 
"description":
                        desc 
subReader.ReadString();
                        break;
                    case 
"pubdate":
                        
string pubDateVal subReader.ReadString();
                        
DateTime d;
                        if 
(DateTime.TryParse(pubDateVal, out d))
                        {
                            pubDate 
Convert.ToDateTime(pubDateVal);
                        
}
                        
break;

                    case 
"author":
                        authorName 
subReader.ReadString();
                        break;
                
}
            }
            
if (!String.IsNullOrEmpty(title)
                && !String.IsNullOrEmpty(link)
                && !String.IsNullOrEmpty(desc))
            {
                RSSItem item 
= new RSSItem(title, link,
                    desc, pubDate, authorName)
;
                return 
item;
            
}
            
return null;
        
}


        
private static RSSItem[] GetRSSItems(Dictionary<string
            List<RSSItem>> namesFeeds, 
int numberToShow)
        {
            
if (numberToShow < 1) numberToShow 1;
            
List<RSSItem> blogItems = new List<RSSItem>();
            int 
0;
            if 
(namesFeeds != null && namesFeeds.Count > 0)
            {
                
foreach (string key in namesFeeds.Keys)
                {
                    List<RSSItem> items 
namesFeeds[key];                    
                    if 
(items != null)
                    {
                        
int count items.Count;
                        if 
(count > 0)
                        {
                            
int 0;
                            while 
(j < numberToShow)
                            {
                                
if (j == count) break;
                                
blogItems.Add(items[j]);
                                
j++;
                                
i++;
                            
}
                        }
                        
else
                        
{
                            namesFeeds.Remove(key)
;
                        
}
                    }
                    
                }
            }
            
else
            
{
                HttpContext.Current.Trace.Warn(
"GetRSSItems"
                    
"namesFeeds is null or has a 0 count.");
            
}
            
return blogItems.ToArray();
        
}
    }
}

 

using System;
using 
System.Collections.Generic;

namespace 
InterfaceTT {

    
public class RSSItem : IComparable<RSSItem> {
        
private string _Title;
        private string 
_Link;
        private string 
_Description;
        private 
DateTime? _PubDate;
        private string 
_AuthorName;

        public 
RSSItem(string title,string link,string desc,
            DateTime? pubDate,
string authorName) {
            _Title 
title;
            
_Link link;
            
_Description desc;
            
_PubDate pubDate;
            
_AuthorName authorName;
        
}

        
public string Title {
            
get {
                
return _Title;
            
}
            
set {
                _Title 
= value;
            
}
        }

        
public string Link {
            
get {
                
return _Link;
            
}
            
set {
                _Link 
= value;
            
}    
        }

        
public string Description {
            
get {
                
return _Description;
            
}
            
set {
                _Description 
= value;
            
}    
        }

        
public DateTime? PubDate
        {
            
get return _PubDate}
            
set { _PubDate = value; }
        }

        
public string AuthorName
        {
            
get return _AuthorName}
            
set { _AuthorName = value; }
        }

        
#region IComparable<RSSItem> Members

        
public int CompareTo(RSSItem other)
        {
            
if (this.PubDate < other.PubDate) return 1;
            if 
(this.PubDate > other.PubDate) return -1;
            return 
0//The are equal
        
}

        
#endregion
    
}
}

The user control that  displays the blog data for employees is shown next.  It uses the ObjectDataSource control to bind to the RssBlogRoller class.

<%@ Control Language="C#" AutoEventWireup="true" 
CodeFile
="BlogRoller.ascx.cs" Inherits="UserControl_BlogRoller" %>

<%@ OutputCache Duration="900" VaryByParam="None" %>
<asp:DataList ID="DataList1" runat="server" 
  DataSourceID
="odsRss" HorizontalAlign="Left" RepeatLayout="Flow">
   
    
<ItemTemplate>
          
<a href='<%# Eval("Link") %>'><%# Eval("Title") %></a>
          
<br />
          
<%# Eval("PubDate") %> By <%# Eval("AuthorName") %>
          
<br />
          
<%# Strip(Eval("Description"),Eval("Link")) %>
        
</li>
    
</ItemTemplate>
  
</asp:DataList>
<asp:ObjectDataSource ID="odsRss" runat="server" 
  SelectMethod
="GetRssItems" TypeName="InterfaceTT.RSSBlogRoller">
    
<SelectParameters>
        
<asp:Parameter DefaultValue="" 
          Name
="rssURLs" Type="String" />
        <
asp:Parameter DefaultValue="1" 
          Name
="numberToShow" Type="Int32" />
    </
SelectParameters>
</asp:ObjectDataSource>

An example of the blog roller in action can be found at http://www.interfacett.com/ and the code can be downloaded here.

comments powered by Disqus

1 Comment

  • The XmlDataSource can certainly be used for simple scenarios. However, this solution grabs RSS feeds from multiple locations and determines how many items to show from each blog. The XmlDataSource doesn't handle those features without writing extra code around it to aggregate, merge the sources and then show a specific number of items.

    Dan

Comments have been disabled for this content.