Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

Windows Phone 7 Series development: reading RSS feeds

Windows Phone 7 Series One limitation on Windows Phone 7 is related to System.Net namespace classes. There is no convenient way to read data from web. There is no WebClient class. There is no GetResponse() method – we have to do it all asynchronously because compact framework has limited set of classes we can use in our applications to communicate with internet. In this posting I will show you how to read RSS-feeds on Windows Phone 7.

NB! This is my draft code and it may contain some design flaws and some questionable solutions. This code is intended to use as test-drive for Windows Phone 7 CTP developer tools and I don’t suppose you are going to use this code in production environment.

Current state of my RSS-reader

My Windows Phone 7 RSS-readerCurrently my RSS-reader for Windows Phone 7 is very simple, primitive and uses almost all defaults that come out-of-box with Windows Phone 7 CTP developer tools.

My first goal before going on with nicer user interface design was making RSS-reading work because instead of convenient classes from .NET Framework we have to use very limited classes from .NET Framework CE. This is why I took the reading of RSS-feeds as my first task.

There are currently more things to solve regarding user-interface. As I am pretty new to all this Silverlight stuff I am not very sure if I can modify default controls easily or should I write my own controls that have better look and that work faster.

The image on right shows you how my RSS-reader looks like right now. Upper side of screen is filled with list that shows headlines from this blog. The bottom part of screen is used to show description of selected posting. You can click on the image to see it in original size.

In my next posting I will show you some improvements of my RSS-reader user interface that make it look nicer. But currently it is nice enough to make sure that RSS-feeds are read correctly.

FeedItem class

As this is most straight-forward part of the following code I will show you RSS-feed items class first. I think we have to stop on it because it is simple one.


public class FeedItem

{

    public string Title { get; set; }

    public string Description { get; set; }

    public DateTime PublishDate { get; set; }

    public List<string> Categories { get; set; }

    public string Link { get; set; }

 

    public FeedItem()

    {

        Categories = new List<string>();

    }

}


RssClient

RssClient takes feed URL and when asked it loads all items from feed and gives them back to caller through ItemsReceived event. Why it works this way? Because we can make responses only using asynchronous methods. I will show you in next section how to use this class.

Although the code here is not very good but it works like expected. I will refactor this code later because it needs some more efforts and investigating. But let’s hope I find excellent solution. :)


public class RssClient

{

    private readonly string _rssUrl;

 

    public delegate void ItemsReceivedDelegate(RssClient client, IList<FeedItem> items);

    public event ItemsReceivedDelegate ItemsReceived;

 

    public RssClient(string rssUrl)

    {

        _rssUrl = rssUrl;

    }

 

    public void LoadItems()

    {

        var request = (HttpWebRequest)WebRequest.Create(_rssUrl);

        var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request);

    }

 

    void ResponseCallback(IAsyncResult result)

    {

        var request = (HttpWebRequest)result.AsyncState;

        var response = request.EndGetResponse(result);

 

        var stream = response.GetResponseStream();

        var reader = XmlReader.Create(stream);

        var items = new List<FeedItem>(50);

 

        FeedItem item = null;

        var pointerMoved = false;

 

        while (!reader.EOF)

        {

            if (pointerMoved)

            {

                pointerMoved = false;

            }

            else

            {

                if (!reader.Read())

                    break;

            }

 

            var nodeName = reader.Name;

            var nodeType = reader.NodeType;

 

            if (nodeName == "item")

            {

                if (nodeType == XmlNodeType.Element)

                    item = new FeedItem();

                else if (nodeType == XmlNodeType.EndElement)

                    if (item != null)

                    {

                        items.Add(item);

                        item = null;

                    }

 

                continue;

            }

 

            if (nodeType != XmlNodeType.Element)

                continue;

 

            if (item == null)

                continue;

 

            reader.MoveToContent();

            var nodeValue = reader.ReadElementContentAsString();

            // we just moved internal pointer

            pointerMoved = true;

 

            if (nodeName == "title")

                item.Title = nodeValue;

            else if (nodeName == "description")

                item.Description =  Regex.Replace(nodeValue,@"<(.|\n)*?>",string.Empty);

            else if (nodeName == "feedburner:origLink")

                item.Link = nodeValue;

            else if (nodeName == "pubDate")

            {

                if (!string.IsNullOrEmpty(nodeValue))

                    item.PublishDate = DateTime.Parse(nodeValue);

            }

            else if (nodeName == "category")

                item.Categories.Add(nodeValue);

        }

 

        if (ItemsReceived != null)

            ItemsReceived(this, items);

    }

}


This method is pretty long but it works. Now let’s try to use it in Windows Phone 7 application.

Using RssClient

And this is the fragment of code behing the main page of my application start screen. You can see how RssClient is initialized and how items are bound to list that shows them.


public MainPage()

{

    InitializeComponent();

 

    SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;

    listBox1.Width = Width;

 

    var rssClient = new RssClient("http://feedproxy.google.com/gunnarpeipman");

    rssClient.ItemsReceived += new RssClient.ItemsReceivedDelegate(rssClient_ItemsReceived);

    rssClient.LoadItems();

}

 

void rssClient_ItemsReceived(RssClient client, IList<FeedItem> items)

{

    Dispatcher.BeginInvoke(delegate()

    {

        listBox1.ItemsSource = items;

    });           

}


Conclusion

As you can see it was not very hard task to read RSS-feed and populate list with feed entries. Although we are not able to use more powerful classes that are part of full version on .NET Framework we can still live with limited set of classes that .NET Framework CE provides.

Comments

Sam Jarawan said:

I recently needed to read a feed in and am using LINQ, here's my version (note I'm not including categories but that would be an easy addition):

private void GenerateList(string itemUri)

{

   WebClient webClient = new WebClient();

   webClient.DownloadStringCompleted += (object sender, DownloadStringCompletedEventArgs e) =>

       {

           if (e.Error != null)

               return;

           XElement xmlDoc = XElement.Parse(e.Result);

           string title = (string)xmlDoc.Element("channel").Element("title");

           feedListBox.ItemsSource = from item in xmlDoc.Element("channel").Elements("item")

                                     select new FeedItemViewModel

                                     {

                                         Title = (string)item.Element("title"),

                                         Description = (string)item.Element("description"),

                                         Link = (string)item.Element("link"),

                                         PublishedDate = item.Element("pubDate") != null ? (DateTime)item.Element("pubDate") : DateTime.MinValue,

                                         VideoUri = GetVideoUri(item),

                                     };

       };

   webClient.DownloadStringAsync(new Uri(itemUri));

}

# April 8, 2010 3:56 PM

DigiMortal said:

Yes, it is possible to load all RSS to memory but I want to avoid that. My goal is to write application that uses minimal resources. I'm not still sure what is the end result but I hope it is good. :)

# May 2, 2010 3:24 AM

RoguePlanetoid said:

Very nice - had a need for a simple RSS feed reader to use as an example, was going to use the Syndication feed support but the latest CTP update has made this more difficult (for an example), this is ideal - using something similar for reading Twitter RSS data.

# May 5, 2010 8:09 AM

marsel said:

I try to test this example but i get only these on the screen of phone simulator. As I'm really new to all stuff please help me because i don't know what to do.

Thanks

# November 6, 2010 6:40 AM

Marsel said:

what i get is this

myapp.FeedItem

myapp.FeedItem

myapp.FeedItem

myapp.FeedItem

myapp.FeedItem

myapp.FeedItem

myapp.FeedItem

# November 6, 2010 6:44 AM

jigarme said:

Can't we use SyndicationFeed from using System.ServiceModel.Syndication?

# January 9, 2011 3:07 PM

Mark said:

Marsel, you need to set the DisplayMemberPath property of the textbox1 to member of FeedItem that you want to display (e.g. Title).

# April 1, 2011 4:37 AM

Prashant said:

I am not able to get the selected item's description.. can you please help..??

# June 7, 2012 10:06 AM