Welcome to irritatedVowel.com Sign in | Help

POKE 53280,0: Pete Brown's Blog

Silverlight, WPF, Woodworking, .NET Programming, CNC, Nature, and other topics.

Pete Brown writes on a number of topics including Silverlight, WPF, .NET, woodworking and working as a consultant in the DC area. On most forums, Pete goes by the name Psychlist1972. Pete has worked at Applied Information Sciences (AIS) since 1996 where he currently performs as a lead architect and project manager.

Subscribe to my feed

Add to Technorati Favorites
Applied Information Sciences - My Employer

Community Events




World Domination

who's online

Networks


View Pete Brown's profile on LinkedIn

AddThis Social Bookmark Button
How to Retrieve and Process an RSS Feed in Silverlight 2

For the Facebook Silverlight 2 Beta 2 application I'm writing, I need to be able to process a number of RSS feeds. In Silverlight 2 Beta 2, processing RSS is, well, really simple :)

Here's a class and associated event and exception classes I wrote to handle downloading the feed, and loading it into the RSS objects:

#region Support Classes (exception, eventargs)

public class FeedException : Exception
{
    public FeedException()
        : base("Exception retrieving or processing feed.")
    {
    }

    public FeedException(string message)
        : base("Exception retrieving or processing feed. " + message)
    {
    }

    public FeedException(string message, Exception innerException)
        : base("Exception retrieving or processing feed. " + message, 
                innerException)
    {
    }

}

public class FeedRetrievedEventArgs : EventArgs
{
    private SyndicationFeed _feed;

    public FeedRetrievedEventArgs(SyndicationFeed feed)
    {
        _feed = feed;
    }

    public SyndicationFeed Feed
    {
        get { return _feed; }
    }

}

public class FeedErrorEventArgs : EventArgs
{
    private Exception _exception;

    public FeedErrorEventArgs(Exception exception)
    {
        _exception = exception;
    }

    public Exception Error
    {
        get { return _exception; }
    }

}

#endregion

public class RssFeedGrabber
{
    public event EventHandler<FeedRetrievedEventArgs> FeedRetrieved;
    public event EventHandler<FeedErrorEventArgs> FeedError;

    private const string _nullResultErrorMessage = 
        "The returned stream was null. "+
        "The site may not have a valid client access policy in place.";
    private const string _parseErrorMessage = 
        "Unable to parse feed.";

    /// <summary>
    /// Makes an async call to return the feed data
    /// </summary>
    /// <param name="url">URL of the feed</param>
    public void RetrieveFeedAsync(Uri url)
    {
        WebClient client = new WebClient();

        client.OpenReadCompleted +=
            new OpenReadCompletedEventHandler(client_OpenReadCompleted);

        client.Encoding = System.Text.Encoding.UTF8;
        client.OpenReadAsync(url);
    }


    /// <summary>
    /// Event handler called when the WebClient returns the data from the call
    /// </summary>
    private void client_OpenReadCompleted(object sender, 
        OpenReadCompletedEventArgs e)
    {
        // process the feed

        if (e.Error == null && e.Result != null)
        {
            using (XmlReader reader = XmlReader.Create(e.Result))
            {
                try
                {
                    SyndicationFeed feed = SyndicationFeed.Load(reader);

                    FeedRetrievedEventArgs args = 
                        new FeedRetrievedEventArgs(feed);

                    OnFeedRetrieved(args);
                }
                catch (Exception ex)
                {
                    // the loader couldn't load the feed
                    FeedErrorEventArgs args = 
                        new FeedErrorEventArgs(
                            new FeedException(_parseErrorMessage, ex));
                    OnFeedError(args);
                }
            }
        }
        else
        {
            if (e.Error != null)
            {
                // there was an error returned from the call
                FeedErrorEventArgs args = new FeedErrorEventArgs(e.Error);
                OnFeedError(args);
            }
            else
            {
                // an empty stream. You get this silent failure when there 
                // is no crossdomain file in place (at least in beta2)
                FeedErrorEventArgs args = 
                    new FeedErrorEventArgs(
                        new FeedException(_nullResultErrorMessage));
                OnFeedError(args);
            }
        }
    }

    /// <summary>
    /// Internal method used to raise the feed event
    /// </summary>
    protected void OnFeedRetrieved(FeedRetrievedEventArgs args)
    {
        if (FeedRetrieved != null)
            FeedRetrieved(this, args);
    }

    /// <summary>
    /// Internal method used to raise the error event
    /// </summary>
    protected void OnFeedError(FeedErrorEventArgs args)
    {
        if (FeedError != null)
            FeedError(this, args);
    }

}

The class simply makes an async web call to retrieve the feed, then raises an event with the parsed feed. If you extend the feed formatter classes, you'll want to modify this code to use the appropriate one. If I end up extending anything, I'll write (and post) a templated version of this class.

Make sure you add a reference to System.ServiceModel.Syndication as well as add the appropriate using statement:

using System.ServiceModel.Syndication;

Keep in mind that the site hosting the rss feed will need to have an appropriate cross domain file in place, or you'll need to use a workaround like the ones described in Tim Heuer's blog post.

To use this class, simply call it from your code like this:

void Page_Loaded(object sender, RoutedEventArgs e)
{
    RssFeedGrabber grabber = new RssFeedGrabber();

    grabber.FeedRetrieved += 
        new EventHandler<FeedRetrievedEventArgs>(grabber_FeedRetrieved);
    grabber.FeedError += 
        new EventHandler<FeedErrorEventArgs>(grabber_FeedError);

    grabber.RetrieveFeedAsync(
        new Uri("http://feeds.feedburner.com/PeteBrown"));
}

void grabber_FeedError(object sender, FeedErrorEventArgs e)
{
    // there was an error with the feed. display appropriate
    // message or take action here
}

void grabber_FeedRetrieved(object sender, FeedRetrievedEventArgs e)
{
    foreach (SyndicationItem item in e.Feed.Items)
    {
        System.Diagnostics.Debug.WriteLine(item.Title.Text);
    }
}

(as an aside, I don't usually break up my code lines as seen above, unless the lines are extremely long; I broke them up just so they fit in this post.)

Let me know if you have any questions or run into any issues, or if you've come up with an even simpler/cooler/more functional version of this class.

  Add to Technorati Favorites
Posted: Friday, June 20, 2008 12:21 PM by Pete.Brown
Filed under: ,

Comments

How to Retrieve and Process an RSS Feed in Silverlight 2 | Silverlight Guide said:

PingBack from http://www.silverlightguide.com/tutorials/how-to-retrieve-and-process-an-rss-feed-in-silverlight-2
# June 21, 2008 4:32 AM

Community Blogs said:

Michael Washington's Silverlight Desktop, Peter Bromberg on Data, Jesse Liberty on new interface
# June 22, 2008 11:23 PM

Christopher Steen said:

ASP.NET Why would you want to write your own WYSIWYG editor? [Via: JoeStagner ] AJAX Extender for TinyMCE...
# June 25, 2008 8:27 AM

Christopher Steen said:

Link Listing - June 24, 2008
# June 25, 2008 8:28 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Enter the text you see in the image:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS