Create RSS and Atom Feeds with LINQ and WCF Syndication in .NET 3.5

Last week after finishing manuscripts of my book, I promised to get back to regular blogging and give more stuff about programming and .NET especially about newly released .NET 3.5 so here you go!  It's been a long time since the last time that I sent a blog post with programming codes, isn't it?!

One of very nice additions to .NET 3.5 is the Syndication library for Windows Communication Foundation which lets you create RSS and Atom feeds and deal with data from existing feeds easily.  You know that there were some good components for this purpose but now that we have a built-in feature for this then .NET developers can write consistent codes for their feeds.

On the other hand, LINQ is a new feature in .NET 3.5 that should be used in any .NET 3.5 application that deals with data.

Applying these two features together, we can fetch data from different data storage systems and create RSS or Atom feeds with syndication library in WCF which is the topic that will be covered in this post.  I show this by giving an example.

Before stepping in the process of doing this, I create an ASP.NET 3.5 Web Application project.

Create the Database

First of all, I create a very simple database with a single table that keeps data for my blog posts.  It has some columns for ID, title, Body, Date and Category and I save some sample data into this table.

Sample Data

Map Entities

Now I add a LINQ to SQL item to my project and add my table to this item as well as another entity for my post categories because I want to select them easily and add them to my feed.

LINQ to SQL

Add References

Before implementing my code, I need to add a reference to System.ServiceModel.Web assembly to my project because it includes the syndication library of WCF in.NET Framework 3.5.

Implement the Logic

The main part is where I implement my feed logic.  I use my Default.aspx page to display the feed content.  The C# code to do this is shown below.

using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.ServiceModel.Syndication;

using System.Xml;

using System.Collections.Generic;

using System.Collections.ObjectModel;

 

namespace SyndicationSample

{

    public partial class _Default : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            DataClassesDataContext dataContext = new DataClassesDataContext();

 

            // Select data

            var itemsQuery = from post in dataContext.Posts

                            select new

                            {

                                post.ID,

                                post.Title,

                                post.Body,

                                post.Date,

                                post.Category

                            };

 

            // Prepare response

            Response.Buffer = false;

            Response.Clear();

            Response.ContentType = "application/xml";

 

            // Create an XmlWriter to write the feed into it

            using (XmlWriter writer = XmlWriter.Create(Response.OutputStream))

            {

                // Set the feed properties

                SyndicationFeed feed = new SyndicationFeed

                    ("Keyvan Nayyeri",

                    "Daily musings about .NET.",

                    new Uri("http://nayyeri.net"));

 

                // Add authors

                feed.Authors.Add(new SyndicationPerson

                    ("someone@somewhere.com",

                    "Keyvan Nayyeri",

                    "http://nayyeri.net"));

 

                // Add categories

                var categoriesQuery = from cat in dataContext.Cats

                                      select cat.Category;

 

                foreach (var category in categoriesQuery)

                {

                    feed.Categories.Add(new SyndicationCategory(category));

                }

 

                // Set copyright

                feed.Copyright = new TextSyndicationContent

                    ("© Copyright 2005-2007 Keyvan Nayyeri");

 

                // Set generator

                feed.Generator = "Keyvan's very own RSS Generator :-D";

 

                // Set language

                feed.Language = "en-US";

 

                // Add post items

                List<SyndicationItem> items = new List<SyndicationItem>();

                foreach (var Post in itemsQuery)

                {

                    SyndicationItem item = new SyndicationItem();

                    item.Id = Post.ID.ToString();

                    item.Title = TextSyndicationContent.CreatePlaintextContent(Post.Title);

                    item.Content = SyndicationContent.CreateXhtmlContent(Post.Body);

                    item.PublishDate = Post.Date;

                    item.Categories.Add(new SyndicationCategory(Post.Category));

 

                    items.Add(item);

                }

                feed.Items = items;

 

                // Write the feed to output

                Rss20FeedFormatter rssFormatter = new Rss20FeedFormatter(feed);

                rssFormatter.WriteTo(writer);

 

                writer.Flush();

            }

            Response.End();

        }

    }

}

All the logic is implemented in the Load event of the page.  First I wrote a query for my blog post items and then prepared my Response object to display XML data for my feed.

WCF syndication uses XmlReader and XmlWriter objects to read or write data for RSS 2.0 or Atom 1.0 feeds.  So I created an XmlWriter based on the Response output stream.

You can write SyndicationFeed or SyndicationItem to the output.  I created a SyndicationFeed as the root and container object for all my feed data and set some properties for my feed.  At the next step I added an author to my feed by using SyndicationPerson object instance.  In the next step, I created another query to fetch categories list and iterated through these categories and added them to my feed categories list via SyndicationCategory object instance.

Setting some properties like copyright, generator name and language was the next step and then I created a list of SyndicationItem objects.  This class represents a single blog post that provides appropriate properties for this purpose.  Iterating through my blog posts and adding them to the list was the last step of fetching data and adding them to my feed objects.

At the end, I used Rss20FeedFromatter to write my feed data into the XmlWriter and showing them to the end user.  I can simply replace this Rss20FeedFormatter with Atom10FeedFormatter to generate an Atom 1.0 feed.

Test the Application

Now I can simply view my page in the browser to see my generated feed.

Output

You can download the source code sample for this post from here.

[advertisement] Axosoft OnTime 2008 is four developer tools in one: bug tracking, project wiki, feature management, and help desk. It manages your development process so developers can focus on coding. Installed or Hosted – Free Single-user license -- Free 30-day team trial.

5 Comments : 11.29.07

Feedbacks

 avatar
#1
Jim Wooley
11.30.2007 @ 6:44 AM
Nice post. I was working on the same, but you beat me to it. FWIW, you can tidy up the code a bit by using object initializers and Feed.Categories.AddAll and Feed.Items.AddAll. This way you can eliminate the explicit for-each iteration. Thus you can re-write your Category population as follows (Note, this code is not tested but should give enough to get a feel for it): // Add categories feed.Categories.AddAll(from cat in dataContext.Cats select new SyndicationCategory(cat.Category)); For a demo using this to query an existing feed, see http://devauthority.com/blogs/jwooley/archive/2007/10/12/85717.aspx.
admin avatar
#2
Keyvan Nayyeri
11.30.2007 @ 7:18 AM
Thank you for the useful comment, Jim :-)
 avatar
#3
Mehrdad Afshari
12.02.2007 @ 2:51 AM
This was the first thing I used while I was demonstrating VS2008 RTM to some friends out there. But I think this specific case is best to be implemented like this in C# 3.0: SyndicationFeed feed = new SyndicationFeed(title, description, new Uri(url), settings.PostCollection.Select(p => { SyndicationItem item = new SyndicationItem() { Title = SyndicationContent.CreatePlaintextContent(p.Title), Content = SyndicationContent.CreateXhtmlContent(p.Body), PublishDate = new DateTimeOffset(p.Date, tzoffset), Id = p.Id.ToString() }; p.Categories.ForEach(cat => item.Categories.Add(cat)); return item; })) { Language = "en-US", Generator = "WCF RSS Generator" }; feed.Authors.Add(new SyndicationPerson(author)); feed.SaveAsRss20(new XmlTextWriter(Response.Output)); To Jim: I don't think there is AddAll extension method to use like that.
 avatar
#4
viswa
07.14.2008 @ 12:36 PM

this articles more helpfull for me.

i have one doubt its u add title, date, id, description.

But u can't add a link or uri...

Please post a code for me . how to add a link or uri

thanks

 avatar
#5
Joe Garett
08.14.2008 @ 2:51 PM

Viswa:

It seems to me that by modifying the base code that Keyvan has given you could in practice add a new column in your table perhaps, called refUrl.

change:

var itemsQuery = from post in dataContext.Posts

select new

{

post.ID,

post.Title,

post.Body,

post.Date,

post.Category

//Added Line

post.refUrl

};

You would then also change:

foreach (var Post in itemsQuery)

{

SyndicationItem item = new SyndicationItem();

item.Id = Post.ID.ToString();

item.Title = TextSyndicationContent.CreatePlaintextContent(Post.Title);

item.Content = SyndicationContent.CreateXhtmlContent(Post.Body);

item.PublishDate = Post.Date;

item.Categories.Add(new SyndicationCategory(Post.Category));

//added line below

item.Links.Add(new SyndicationLink(new Uri(Post.refUrl)), "alternate", Post.Title, "text/html", 1000);

items.Add(item);

}

Or I believe that this is pretty close to what your looking for.

Leave a Comment