How to consume an XML feed in ASP.NET – RSS

Posted by William on Jul 26, 2009

XML is the standard for distributing content on the internet, however it can prove a challenge when trying to consume and handle the data retrieved from an XML document. This is the first in a two part series on consuming and displaying XML content on your own website. We will be using XPathDocument and XPathNavigator to select the information we want from the XML document and a simple repeater to display the information within our own website. I will also show a ridiculously easy technique that can be used to cache the consumed content so that every request to your site does not require a round trip to the XML document. Part one will use an RSS feed as the XML document, part two will use the same techniques to consume a Twitter feed.

We will be performing the following steps to display the RSS feed.

  1. Setting up the current project in Visual Studio
  2. Create a control for displaying the RSS feed data
  3. Make the control reusable
  4. Request the remote RSS feed and bind it to a repeater
  5. Handle each individual ItemDataBound event in the repeater
  6. Cache the results of the RSS feed request

Let’s get started.

Setting up the current project in Visual Studio

First, open Visual Studio and create a new website. Name the website remote-xml.
(i.e. C:sitesremote-xml)
remotexml-1

Your new website should have a default structure of App_Data, Default.aspx and web.config. You can delete the App_Data folder if you wish, we will not be using it in this tutorial.
remotexml-2

Create a new folder called App_Code. Then create a new folder called controls. Within the controls folder add a new control called rss-feed.ascx.
remotexml-3

Open Default.aspx and add the new rss-feed.ascx control to it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register src="controls/rss-feed.ascx" tagname="RssFeed" tagprefix="wd" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
 
        <wd:RssFeed ID="ctrRssFeed" runat="server" />
 
    </div>
    </form>
</body>
</html>

Create a control for displaying the RSS feed data

Now we need to write the rendering markup for this control. Open the new control and add a heading and a repeater to its markup. The repeater will need an ItemTemplate and SeparatorTemplate.
ItemTemplate : This will hold the controls that display the common RSS components (title, description and link)
SeparatorTemplate: This will be rendered between each ItemTemplate in the repeater

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<h1>My RSS Feed</h1>
 
<asp:Repeater ID="rptRssFeed" runat="server">
    <ItemTemplate>
        <div>
            <asp:Literal ID="litTitle" runat="server" /><br />
            <asp:Literal ID="litDescription" runat="server" /><br />
            <asp:HyperLink ID="hypLink" Text="View" runat="server" />
        </div>
    </ItemTemplate>
    <SeparatorTemplate>
        <hr />
    </SeparatorTemplate>
</asp:Repeater>

When we bind our RSS feed to the repeater we will want to handle each item that is bound to the repeater. In order to do this we need to handle the OnItemDataBound event. Let’s add the handler for this event to our repeater.

1
<asp:Repeater ID="rptRssFeed" OnItemDataBound="rptRssFeed_ItemDataBound" runat="server">

We will also need to add the event handler code to the codebehind file.

1
2
3
4
protected void rptRssFeed_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
 
}

You can style the repeater’s item template however you wish. For example, if you want the title of each feed item to be a heading you can alter the ItemTemplate to include the required html.

1
2
3
4
5
6
7
8
9
...
    <ItemTemplate>
        <div>
                <h3><asp:Literal ID="litTitle" runat="server" /></h3>
                <asp:Literal ID="litDescription" runat="server" /><br />
                <asp:HyperLink ID="hypLink" Text="View" runat="server" />
        </div>
    </ItemTemplate>
...

If you run your code now you should see something similar to the following, not much to look at but better than an exception!
remotexml-4

Make the control reusable

The control is not much use unless it can be reused with different RSS feeds. To do this we will expose a property of the control that allows setting of the RSS url at the point of creation, or even dynamically if you choose to do so!

Add the following property to the codebehind file of the control

1
2
3
4
5
6
private string _feedUrl;
public string FeedUrl
{
    get { return _feedUrl; }
    set { _feedUrl = value; }
}

Now you can specify the RSS feed in the declarative markup of your ASPX page.

1
<wd:RssFeed ID="ctrRssFeed" FeedUrl="http://www.wduffy.co.uk/blog/feed/" runat="server" />

Request the remote RSS feed and bind it to a repeater

The control is now ready to display the contents of the RSS Feed. So we need to request it. In the Page_Init event of the control we will use the XPathDocument to load the feed and return an XPathNavigator. The XPathDocument takes a single argument in its constructor; the location of an XML file. I have used my own RSS feed as an example, but you can swap this for your own if you wish. Calling CreateNavigator on the XPathDocument returns an XPathNavigator, which allows easy traversal of the RSS feed’s XML tree using XPath.

We will be using the System.Xml and System.Xml.XPath namespaces so make sure you include these in your control’s using statement list.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
...
using System.Xml;
using System.Xml.XPath;
 
public partial class controls_rss_feed : System.Web.UI.UserControl
{
 
    private string _feedUrl;
    public string FeedUrl
    {
        get { return _feedUrl; }
        set { _feedUrl = value; }
    }
 
    private XmlNamespaceManager _xmlnsm;
 
    protected void Page_Init(object sender, EventArgs e)
    {
        XPathNavigator xpn = new XPathDocument(_feedUrl).CreateNavigator();
        _xmlnsm = XmlHelper.GetXmlNameSpaceManager(xpn);
 
        rptRssFeed.DataSource = xpn.Select("/x:rss/x:channel/x:item", _xmlnsm);
        rptRssFeed.DataBind();
    }
 
    protected void rptRssFeed_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
 
    }
 
}

One thing to note is that we are creating an XmlNamespaceManager object. If you look at where the repeater datasource is being set you will see the .Select query uses x: to resolve nodes in the XML tree (we set x: to the default namespace when creating the XmlNamespaceManager). Also notice that the _xmlnsm object is in the global scope of the control. This is because we will use it again within each of the raised ItemDataBound events.

The XmlNameSpaceManager is required when using XPath to ensure that namespaces are properly resolved during queries. Understanding XML namespaces is outwith the scope of this tutorial but I would recommend you check out this simple guide on W3Schools. In the meantime, create a new Class in the App_Code folder called XmlHelper. Make this class static and add the following static method to it for easy creation of future XmlNamespaceManager objects. If you don’t understand what this code does don’t worry, just copy paste it into the XmlHelper file you just created.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.XPath;
 
public static class XmlHelper
{
 
    public static XmlNamespaceManager GetXmlNameSpaceManager(XPathNavigator xpn)
    {
        xpn.MoveToFollowing(XPathNodeType.Element);
 
        XmlNamespaceManager xmlnsm = new XmlNamespaceManager(xpn.NameTable);
        xmlnsm.AddNamespace("x", xpn.NamespaceURI);
 
        foreach (KeyValuePair<string, string> xns in xpn.GetNamespacesInScope(XmlNamespaceScope.All))
            xmlnsm.AddNamespace(xns.Key, xns.Value);
 
        return xmlnsm;
    }
 
}

Handle each individual ItemDataBound event in the repeater

Now that we have the control’s repeater marked up and the XPathNavigator is bound to it’s DataSource we need to display the values of each item. Within the rptRssFeed_ItemDataBound event handler we will work with the XPathNavigator object (which is passed as the current dataitem) to extract the nodes we need and display their data in the repeater’s controls.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void rptRssFeed_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        XPathNavigator xpn = (XPathNavigator)e.Item.DataItem;
        Literal litTitle = (Literal)e.Item.FindControl("litTitle");
        Literal litDescription = (Literal)e.Item.FindControl("litDescription");
        HyperLink hypLink = (HyperLink)e.Item.FindControl("hypLink");
 
        litTitle.Text = xpn.SelectSingleNode("x:title", _xmlnsm).Value;
        litDescription.Text = xpn.SelectSingleNode("x:description", _xmlnsm).Value;
        hypLink.NavigateUrl = xpn.SelectSingleNode("x:link", _xmlnsm).Value;
    }
}

Cache the results of the RSS feed request

All that’s left to do is add a single line of code to ensure that the RSS feed is not requested every time your website gets a visitor. On the control’s .ascx page below its main <%@ Control … %> declaration simply add the following line to cache the feed for 60 minutes, after which a brand new request will be made. (The duration property takes its value in seconds)

1
<%@ OutputCache Duration="3600" VaryByParam="none" %>

Conculsion

Hopefully you now have a control that will read a remote RSS feed, render its contents and cache the output. You should be able to use these same techniques to query any XML file and render it’s contents; something that the next part of this tutorial will cover.