SyndicationFeed.Load - The easy way to read an RSS feed

I always found writing code to read an RSS feed within my .NET application very time-consuming and long-winded. My RSS code was always a combination of using WebRequest, WebResponse, Stream, XmlDocument, XmlNodeList and XmlNode. That’s a lot of classes just to read an RSS feed.

Yesterday, I stumbled on an interesting piece of code on my favourite programming site StackOverflow.com, where someone asked how to parse an RSS feed in ASP.NET. The answer was surprisingly simple. RSS feeds can now be consumed using the System.ServiceModel.Syndication namespace in .NET 3.5 SP1. All you need is two lines of code:

var reader = XmlReader.Create("http://mysite.com/feeds/serializedFeed.xml");
var feed = SyndicationFeed.Load(reader);

Here’s a full example on how we can iterate through through the SyndicationFeed class:

public static List<BlogPost> Get(string rssFeedUrl)
{
    var reader = XmlReader.Create(rssFeedUrl);
    var feed = SyndicationFeed.Load(reader);

    List<BlogPost> postList = new List<BlogPost>();

    //Loop through all items in the SyndicationFeed
    foreach (var i in feed.Items)
    {
        BlogPost bp = new BlogPost();
        bp.Title = i.Title.Text;
        bp.Body = i.Summary.Text;
        bp.Url = i.Links[0].Uri.OriginalString;
        postList.Add(bp);
    }

    return postList;
}

That’s too simple, especially when compared to the 70 lines of code I normally use to do the exact same thing.

Use YouTubes RSS Feed To Output A List of Videos

Ok! I admit it! I posted some incorrect information from one of my previous blog posts to “Dynamically Output A List of YouTube Video’s In ASP.NET”. I stupidly said: “The RSS feed is not structured in a nice enough format to output all the information you may need with ease.” I must have been drunk when I wrote that. As you can see from a sample of their RSS feed below I was wrong:

<entry>
  <id>http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic</id>
    <published>2009-05-31T17:01:12.000Z</published>
    <updated>2009-06-01T01:22:11.000Z</updated>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='bike'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Podcast'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Pedrosa'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='motorcycles'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Honda+RC212V'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='speed'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Suzuki+GSV-R800'/>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat' term='Sports' label='Sport'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Rossi'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='motorcycle+road+racing'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='motograndprix'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Yamaha+YZR+M1'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Mugello'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Italy'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Stoner'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Ducati+Desmosedici+GP8'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='MotoGP'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Lorenzo'/>
    <title type='text'>MotoGP action from Mugello 2009</title>
    <content type='text'>The best of the action from the Gran Premio D&amp;#180;Italia Alice, the fifth round of the 2009 motogp World Championship.</content>
    <link rel='alternate' type='text/html' href='http://www.youtube.com/watch?v=R6r2ckeIpic'/>
    <link rel='http://gdata.youtube.com/schemas/2007#video.responses' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic/responses'/>
    <link rel='http://gdata.youtube.com/schemas/2007#video.related' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic/related'/>
    <link rel='self' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/users/motogp/uploads/R6r2ckeIpic'/>
    <author>
      <name>MotoGP</name>
      <uri>http://gdata.youtube.com/feeds/api/users/motogp</uri>
    </author>
    <gd:comments>
      <gd:feedLink href='http://gdata.youtube.com/feeds/api/videos/R6r2ckeIpic/comments' countHint='24'/>
    </gd:comments>
    <media:group>
      <media:category label='Sport' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>Sports</media:category>
      <media:description type='plain'>The best of the action from the Gran Premio D&amp;#180;Italia Alice, the fifth round of the 2009 motogp World Championship.</media:description>
      <media:keywords>MotoGP, Italy, Mugello, Podcast, Stoner, Pedrosa, Rossi, Lorenzo, Yamaha+YZR+M1, Ducati+Desmosedici+GP8, Honda+RC212V, Suzuki+GSV-R800, motorcycle+road+racing, motograndprix, motorcycles, bike, speed</media:keywords>
      <media:player url='http://www.youtube.com/watch?v=R6r2ckeIpic'/>
      <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/2.jpg' height='90' width='120' time='00:00:38.500'/>
      <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/1.jpg' height='90' width='120' time='00:00:19.250'/>
      <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/3.jpg' height='90' width='120' time='00:00:57.750'/>
      <media:thumbnail url='http://i.ytimg.com/vi/R6r2ckeIpic/0.jpg' height='240' width='320' time='00:00:38.500'/>
      <media:title type='plain'>MotoGP action from Mugello 2009</media:title>
      <yt:duration seconds='77'/>
    </media:group>
    <yt:noembed/>
    <gd:rating average='4.862069' max='5' min='1' numRaters='29' rel='http://schemas.google.com/g/2005#overall'/>
    <yt:statistics favoriteCount='10' viewCount='1055'/>
</entry>
<entry>
    ...
</entry>
<entry>
    ...
</entry>

Each “entry” element within the RSS feed represents a YouTube video. You are able to extrapolate all the important information about each movie such as Average Score, View Count, Thumbnail Images, Video Description, etc. Really useful stuff!

You may be thinking: Why should I use an RSS feed to retrieve the video information rather than using the YouTube API? Well, using a YouTube API is definitely the easier and most straight-forward method. But what you should be aware that the API only works from .NET 2.0 onwards. There isn’t a YouTube API for .NET 1.1. Unfortunately, I only found this out when I tried to implement the API into one of my .NET 1.1 client sites.

The code I have written below, reads the YouTube RSS feed and stores the information in a DataTable.

private void GetYouTubeData(string YouTubeUrl)
{
    //Create DataTable to store specific YouTube information
    DataTable dtYouTubeVideoData = new DataTable();
    dtYouTubeVideoData.Columns.Add("YouTubeID");
    dtYouTubeVideoData.Columns.Add("Title");
    dtYouTubeVideoData.Columns.Add("Description");
    dtYouTubeVideoData.Columns.Add("ImageUrl");
    dtYouTubeVideoData.Columns.Add("AverageRatings");
    dtYouTubeVideoData.Columns.Add("ViewCount");

    DataRow drYouTubeVideoData;

    //Link to YouTube RSS feed
    XmlTextReader rssReader = new XmlTextReader(YouTubeUrl);
    XmlDocument xmlDoc = new XmlDocument();

    //Download the XML (via the XmlTextReader)
    xmlDoc.Load(rssReader);

    //Select all nodes starting with "entry"
    XmlNodeList xmlNodeList = xmlDoc.GetElementsByTagName("entry");
    
    //For each "entry" element found
    foreach (XmlNode node in xmlNodeList)
    {
        drYouTubeVideoData = dtYouTubeVideoData.NewRow();

        //Create a new document, to search through the inner contents
        XmlDocument innerXmlDocument = new XmlDocument();
        innerXmlDocument.LoadXml(node.OuterXml);

        // Get movie ID
        drYouTubeVideoData["YouTubeID"] = innerXmlDocument.GetElementsByTagName("id")[0].InnerText.Replace("http://gdata.youtube.com/feeds/api/videos/", "");

        // Get movie title
        drYouTubeVideoData["Title"] = innerXmlDocument.GetElementsByTagName("title")[0].InnerText;

        //Get movie description
        drYouTubeVideoData["Description"] = innerXmlDocument.GetElementsByTagName("content")[0].InnerText;
        
        //Get the thumbnails
        XmlNodeList mediaTumbnail = innerXmlDocument.GetElementsByTagName("media:thumbnail");

        //Iterate through each thumbnail and only get one thumbnail per <entry>.
        foreach (XmlNode thumbnailNode in mediaTumbnail)
        {
            if (thumbnailNode.Attributes["height"].Value == "90" && thumbnailNode.Attributes["url"].Value.EndsWith("1.jpg"))
            {
                drYouTubeVideoData["ImageUrl"] = thumbnailNode.Attributes["url"].Value;
            }
        }

        //Get movie rating
        XmlNodeList ratings = innerXmlDocument.GetElementsByTagName("gd:rating");

        foreach (XmlNode ratingsNode in ratings)
        {
            drYouTubeVideoData["AverageRatings"] = ratingsNode.Attributes["average"].Value;
        }

        //Get Statistics
        XmlNodeList statistics = innerXmlDocument.GetElementsByTagName("yt:statistics");

        foreach (XmlNode statisticsNode in statistics)
        {
            drYouTubeVideoData["ViewCount"] = statisticsNode.Attributes["viewCount"].Value;
        }

        dtYouTubeVideoData.Rows.Add(drYouTubeVideoData);
    }

    rssReader.Close();

    //Bind YouTube data to repeater
    repVideoList.DataSource = dtYouTubeVideoData;
    repVideoList.DataBind();        
}