information

 Checkout

 Følg udviklingen ...

 Vær årvågen ...

 Tag chancer ...

"Vær altid parat til at udforske verdenen med dens omskiftende teknologiske udvikling"

Mere info...

"Et anderledes CMS system med uanede muligheder, som sætter kunden i centrum med maximal grad af fleksibilitet"

mail
Validering XHTML 1.0 Strict
og Css

 

RSS feeds

How to create a syndication feed for your website


URLhttp://dotnetslackers.com/articles/aspnet/How-to-create-a-syndication-feed-for-your-website.aspx

Introduction

Virtually every website that produces new content on a regular or semi-regular basis provides a syndication feed. Syndication feeds were first used with blogs as a means for sharing the most recent entries, but soon spread to news sites. For instance, CNN.com has a feed that syndicates their breaking news headlines and one that syndicates the latest sports news, along with many others. Today, syndication feeds are used to share all sort of content: Flickr syndicates each user's most recently uploaded images; each project in CodePlex (Microsoft's open-source project hosting website) has a feed that syndicates the latest releases; and Twitter syndicates each user's most recent tweets.

A syndication feed contains information about the most recently published items using a standardized XML format. Because the syndication feed conforms to a known XML standard, its data can be parsed by any computer program that knows how to work with the syndication standard. For example, you can subscribe to various syndication feeds using Microsoft Outlook's RSS Feeds folder. Adding a feed to this folder displays the syndication feed's content items; furthermore, Outlook automatically checks the syndication feed every so often to determine if there is new content. Syndication feeds are also routinely consumed by other websites. The ASP.NET Forums includes a feed that syndicates the 25 most recent posts. This feed is consumed and displayed in the ASP.NET Developer Center on Microsoft's MSDN website. Similarly, you could consume the Twitter feed that syndicates your latest tweets and display them on your blog.

Creating and consuming syndication feeds from an ASP.NET application is a walk in the park thanks to the classes in the System.ServiceModel.Syndication namespace. This article shows how to use these classes to create a syndication feed for your website as well as how to use them to consume and display syndication feeds from other websites. These techniques are demonstrated in a demo web application, which is a website for a fictional book company, Nile.com. This demo site includes a feed that syndicates the most recently published book titles; it also consumes and displays the headlines syndicated by RareBookNews.com.

A Bit of History

Before we delve into the meat of this article it would be worthwhile to spend a moment reviewing the history of syndication standards and the support for working with syndication feeds in .NET. The first syndication feed standard was proposed by Dave Winer in 1997. Over the years this initial syndication standard morphed into what is today known as RSS. The RSS specification was frozen in 2003 with the release of RSS 2.0.

Shortly after RSS 2.0 was released, Sam Ruby proposed a new syndication format to address the shortcomings of the now frozen RSS standard. Over the next several months Ruby and others created a new syndication format named Atom. The Atom 1.0 standard was ratified by the Internet Engineering Task Force (IETF) in 2007.

The .NET Framework did not provide any built-in functionality for creating or consuming syndication feeds until version 3.5 with the introduction of the System.ServiceModel.Syndication namespace. The most germane class in this namespace is SyndicationFeed. As you can probably guess from its name, this class represents a syndication feed. It has properties like Title, Description, Links, and Copyright, which provide details about the feed. The content items that make up the feed are specified via the Items property, which is a collection of SyndicationItem objects. The SyndicationFeed class also has a static Load method that parses and loads the information from a specified RSS 2.0 or Atom 1.0 syndication feed.

In addition to the SyndicationFeed and SyndicationItem classes, the System.ServiceModel.Syndication namespace also includes two formatter classes, Atom10FeedFormatter and Rss20FeedFormatter. These classes take a SyndicationFeed object and generate the corresponding XML content that conforms to either the Atom 1.0 or RSS 2.0 specificiations.

Note:

In 2000 a group at O'Reilly created their own syndication format standard that differed from the then current RSS 0.91 standard. Unfortunately, this group named their new syndication format RSS 1.0, even though it was not related to RSS 0.91 (which later became RSS 2.0). Therefore, RSS 2.0 and RSS 1.0 are significantly different from one another. Similarly, a number of sites started using Atom before it was standardized by the IETF, most notably Google. As a result, many of Google's Atom syndication feeds still use Atom 0.3 instead of Atom 1.0.

The SyndicationFeed class can only parse feeds that conform to the RSS 2.0 or Atom 1.0 standards. The good news is that the vast majority of the syndication feeds on the web use one of these two standards. And if you need to parse an RSS 1.0 or Atom 0.3 feed you can translate the XML content into Atom 1.0-compliant XML on the fly before loading it into a SyndicationFeed object. For more information on this technique check out Daniel Cazzulino's blog entry on upgrading Atom 0.3 feeds on the fly.

Creating a Syndication Feed For Your Website

Every website that routinely publishes any kind of content should offer a syndication feed. A syndication feed can be a static XML file that gets created automatically whenever new content is published or it can be a dynamic web page that gets the latest published items and emits the appropriate XML markup. The demo website uses the latter method.

Creating a syndication feed from a dynamic web page involves three steps:

  1. Create a page that generates the feed's content.
  2. Get the most recently published items to appear in the syndication feed.
  3. Generate and output the feed's XML markup.

Let's walk through each of these steps.

Creating the Syndication Feed Web Page

The syndication feed web page's output is generated programmatically using the classes in the System.ServiceModel.Syndication namespace. Therefore, when creating this page make sure you do not associate it with a master page; once the page has been created remove all of the content from the.aspx page except for the @Page directive.

The demo website's syndication feed is implemented by the Feed.aspx page. The contents of the .aspx page follow:

1.<%@ Page Language="C#" AutoEventWireup="true" 
2.  
3.CodeFile="Feed.aspx.cs" 
4.   Inherits="Feed" %> <%@ OutputCache Duration="60" VaryByParam="Type" %>
5.<%-- That's it! No other content is needed in the .aspx page. --%>

Note that in addition to the @Page directive the .aspx portion also includes an @OutputCache directive. The @OutputCache directive caches the content returned by the syndication feed for the specified Duration - in this case, 60 seconds. In other words, when the first user requests the syndication feed the XML output is cached. For the next 60 seconds, requests for the syndication feed return the XML output stored in the cache rather than having it regenerated by the page. The VaryByParam attribute indicates that the output caching engine should maintain a separate cached output for each unique Type value. As we'll see shortly, the Feed.aspx page accepts an optional Type querystring parameter that indicates the syndication format used. Visiting Feed.aspx or Feed.aspx?Type=Atom returns the syndicated content in accordance with the Atom 1.0 standard, whereas visiting Feed.aspx?Type=RSS returns XML that is in accordance with the RSS 2.0 standard.

For more information on output caching check out my article, Output Caching in ASP.NET.

Retrieving the Most Recently Published Items

The demo application's underlying author and title information comes from the pubs database, which you'll find in the App_Data folder, and uses LINQ to SQL as the Data Access Layer. The LINQ to SQL classes are defined in the Pubs.dbml file, which you'll find in the App_Code folder.

The Page_Load event handler in Feed.aspx starts with the following statement, which retrieves the books from the Titles table ordered in reverse chronological order of their publish date.

1.var dataItems = from book in db.Titles
2.                orderby book.pubdate descending
3.                select book;

That was easy!

Generating the Syndication Feed's XML Output

The last step is to turn the most recently published items into the appropriate syndication feed XML markup. After the dataItems variable is created (see the above code snippet) the Feed.aspx page defines a constant that specifies the maximum number of recently published items to include in the feed and then determines whether to generate an RSS 2.0 or Atom 1.0 syndication feed. The value of the Type querystring parameter dictates which syndication standard is used.

1.// Determine the maximum number of items to show in the feed
2.const int maxItemsInFeed = 10;
3.// Determine whether we're outputting an Atom or RSS feed
4.bool outputRss = (Request.QueryString["Type"] == "RSS");
5.bool outputAtom = !outputRss;

Regardless of what syndication standard you use, the code for constructing the SyndicationFeed object is (mostly) identical. There are a few edge cases that we'll address momentarily. However, the final lines of code that render the SyndicationFeed object into the appropriate XML markup differ based on the syndication standard. Furthermore, the syndication feed should send back a different Content-Type header depending on the syndication format: application/atom+xml for Atom 1.0 feeds and application/rss+xml for RSS 2.0 feeds.

1.// 
2.  
3.Output the appropriate ContentType
4.if (outputRss)
5.    Response.ContentType = "application/rss+xml";
6.else if (outputAtom)
7.    Response.ContentType = "application/atom+xml";

We are now ready to create the SyndicationFeed object and set its properties. As you can see, there are a number of properties associated with the syndication feed, such as: Title, Description, Links, Copyright, and Language, among others.

01.// Create the feed and specify the feed's attributes SyndicationFeed myFeed = new SyndicationFeed();
02.myFeed.Title = TextSyndicationContent
03.               .CreatePlaintextContent("Published Books by Nile.com");
04.myFeed.Description = TextSyndicationContent
05.               .CreatePlaintextContent(@"A syndication of the most recently 
06.                     published books by Nile.com.");
07.myFeed.Links.Add(SyndicationLink.CreateAlternateLink(
08.   new Uri(GetFullyQualifiedUrl("~/Default.aspx"))));
09.myFeed.Links.Add(SyndicationLink.CreateSelfLink(
10.   new Uri(GetFullyQualifiedUrl(Request.RawUrl))));
11.myFeed.Copyright = TextSyndicationContent
12.               .CreatePlaintextContent("Copyright Nile.com Bookstore");
13.myFeed.Language = "en-us";

There is one method used in the above code snippet that is not part of the .NET Framework, and that's GetFullyQualifiedUrl (it is defined further down in the code-behind class). This method accepts a relative URL like ~/Default.aspx and returns the fully qualified URL, like http://www.example.com/Default.aspx.

The next step is to define the syndication feed's items. This is done by creating a List of SyndicationItem objects that contains a SyndicationItem instance for each item to appear in the feed. Once this List has been constructed it can be assigned to the SyndicationFeed object's Items property.

01.// Create 
02.  
03.and populate a list of SyndicationItems
04.List<SyndicationItem> feedItems = new List<SyndicationItem>();
05.foreach (Title t in dataItems.Take(maxItemsInFeed))
06.{
07.    // Atom items MUST have an author, so if there are no authors for this 
08.    // content item then go to next item in loop
09.    if (outputAtom && t.TitleAuthors.Count == 0)
10.        continue;
11.    SyndicationItem item = new SyndicationItem();
12.    item.Title = TextSyndicationContent.CreatePlaintextContent(t.title1);
13.    item.Links.Add(SyndicationLink.CreateAlternateLink(
14.       new Uri(GetFullyQualifiedUrl("~/Titles.aspx"))));
15.    item.Summary = TextSyndicationContent.CreatePlaintextContent(t.notes);
16.    item.Categories.Add(new SyndicationCategory(t.type));
17.    item.PublishDate = t.pubdate;
18.    foreach (TitleAuthor ta in t.TitleAuthors)
19.    {
20.        SyndicationPerson authInfo = new SyndicationPerson();
21.        authInfo.Email = ta.Author.au_lname + "@example.com";
22.        authInfo.Name = ta.Author.au_fullname;
23.        item.Authors.Add(authInfo);
24.        // RSS feeds can only have one author, so quit loop after first author has been added
25.        if (outputRss)
26.            break;
27.    }
28.    // Add the item to the feed
29.    feedItems.Add(item);
30.}
31.myFeed.Items = feedItems;

The foreach loop uses the Take method to iterate through only the first maxItemsInFeed number of books in the dataItems collection. In each iteration a SyndicationItem object is created, its properties are set, and the object is added to feedItems, the List of SyndicationItems created immediately before the start of the loop. Note that the Links collection for each SyndicationItems object contains a link to the Titles.aspx page. Typically each content item has a unique URL, such as http://www.example.com/ShowBook.aspx?ID=34, or http://www.example.com/titles/Life_Without_Fear, and those unique URLs would be what you would link to. However, I did not add such a unique page for each book for this demo and therefore decided to have all content items link to the same URL.

There are two checks I added here to ensure that the information added to the feed conforms the the syndication specification being used. At the top of the loop you can see that I bypass adding the current book to the feed's collection of SyndicationItems if there are no authors for the book. This is because the Atom 1.0 specification requires author information with each item. I could have alternatively added a "dummy" author value for such books, with a name and e-mail address of "Unknown" and "unknown@example.com", for example. (No such check is needed when generating an RSS 2.0 feed as the author information is optional in the RSS 2.0 spec.) The second check is at the end of the inner foreach loop, which adds the author information to the current SyndicationItem object. Because the RSS 2.0 specification allows no more than one author we must break out of this loop after the first iteration to ensure that multiple authors are not added.

The final step is to generate the XML markup for the syndication feed and output it to the Response stream. This is handled via an XmlWriter object and either the Atom10FeedFormatter or Rss20FeedFormatter class, depending on whether you want to generate an Atom 1.0 or RSS 2.0 feed.

01.// Return the feed's XML content as the response
02.XmlWriter feedWriter = XmlWriter.Create(Response.OutputStream);
03.if (outputAtom)
04.{
05.    // Use Atom 1.0        
06.    Atom10FeedFormatter atomFormatter = new Atom10FeedFormatter(myFeed);
07.    atomFormatter.WriteTo(feedWriter);
08.}
09.else if (outputRss)
10.{
11.    // Emit RSS 2.0
12.    Rss20FeedFormatter rssFormatter = new Rss20FeedFormatter(myFeed);
13.    rssFormatter.WriteTo(feedWriter);
14.}
15.feedWriter.Close();

The XmlWriter object feedWriter sends its output to the Response object's OutputStream. Next, either an Atom10FeedFormatter or Rss20FeedFormatter class is instantiated and its WriteTo method is called, which emits the rendered markup to feedWriter, which outputs it to the client.

That's it! We now have a fully functional syndication feed that can emit either RSS 2.0 or Atom 1.0 XML. For example, visting Feed.aspx?Type=RSS returns the following content:

01.<?xml 
02.  
03.version="1.0" encoding="utf-8"?>
04.<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
05.  <channel>
06.    <title>Published Books by Nile.com</title>
07.    <link>http://localhost:56573/Code/Default.aspx</link>
08.    <description>A syndication of the most recently published books by
09.                  Nile.com.</description>
10.    <language>en-us</language>
11.    <copyright>Copyright Nile.com Bookstore</copyright>
12.    <a10:link rel="self" href="http://localhost:56573/Code/Feed.aspx?Type=RSS" />
13.    <item>
14.      <link>http://localhost:56573/Code/Titles.aspx</link>
15.      <author>Locksley@example.com</author>
16.      <category>popular_comp</category>
17.      <title>Net Etiquette</title>
18.      <description>A must-read for computer conferencing.</description>
19.      <pubDate>Sun, 06 Aug 2000 01:33:54 -0700</pubDate>
20.    </item>
21.    <item>
22.      <link>http://localhost:56573/Code/Titles.aspx</link>
23.      <category>UNDECIDED   </category>
24.      <title>The Psychology of Computer Cooking</title>
25.      <description />
26.      <pubDate>Sun, 06 Aug 2000 01:33:54 -0700</pubDate>
27.    </item>
28.    ...
29.  </channel>
30.</rss>

Consuming a Syndication Feed

In addition to creating and rendering syndication feeds, the SyndicationFeed class can also be populated from an existing syndication feed. With a few lines of code you can build a SyndicationFeed object from an RSS 2.0 or Atom 1.0 feed from another site and then display it in a web page. The Default.aspx page in the demo application provides such functionality, pulling the recent headlines from the RareBookNews.com syndication feed, http://www.rarebooknews.com/index.xml. To load the contents of a syndication feed use the SyndicationFeed class's Load method, passing in an XmlReader instance. Once the SyndicationFeed has been loaded you can bind its Items collection to a data Web control.

The Default.aspx page includes a ListView control named BookNewsList and the following code in the Page_Load event handler:

01.// See if feed data is in the cache
02.IEnumerable<SyndicationItem> items = 
03.   Cache["RareBooksFeed"] as IEnumerable<SyndicationItem>;
04.if (items == null)
05.{
06.    // Not in cache, go get it!
07.    try
08.    {
09.        SyndicationFeed rareBookNews = 
10.      SyndicationFeed.Load(XmlReader.Create("http://www.rarebooknews.com/index.xml"));
11.        items = rareBookNews.Items;
12.    }
13.    catch
14.    {
15.        items = new List<SyndicationItem>();
16.    }
17.    // Add the items to the cache
18.    Cache.Insert("RareBooksFeed", items, null, DateTime.Now.AddHours(1.0),
19.       TimeSpan.Zero);
20.}
21.BookNewsList.DataSource = items;
22.BookNewsList.DataBind();

As you can see, the SyndicationFeed object's Items collection is cached for one hour. It's good netiquette to cache the syndication feed rather than re-requesting it every single time someone visits this page. It's also important to load the SyndicationFeed object in a try...catch block so that you can gracefully recover if the RareBookNews.com site is down.

The BookNewsList ListView's ItemTemplate emits the HTML returned by the DisplayFeedItem method, which is defined in the Default.aspx page's code-behind class. This method takes in a SyndicationItem object and generates the HTML for display. Specifically, it creates a hyperlink that points to the content items URL and displays the title as text. It also shows the item's published date and description.

01.protected string 
02.  
03.DisplayFeedItem(SyndicationItem item)
04.{
05.    string itemLink = "#";
06.    if (item.Links.Count > 0)
07.        itemLink = item.Links[0].Uri.ToString();
08.    return string.Format(@"<b><a href=""{0}"" target=""_blank"">{1}</a>
09.                             </b> ({2:d})<br />{3}", 
10.                            itemLink, 
11.                            item.Title.Text,
12.                            FormatPublishDate(item.PublishDate.DateTime), 
13.                            item.Summary.Text);
14.}

Figure 1 shows the Default.aspx page when viewed through a browser. The text circled in red were the latest news headlines from RareBookNews.com at the time of writing.

Figure 1: The RareBookNews.com Headlines Are Displayed In Default.aspx

The 

RareBookNews.com Headlines Are Displayed In Default.aspx

Conclusion

Syndication has quickly grown from a technology that was strictly the domain of blogs to one that is embraced by all sorts of websites that routinely publish content. Creating RSS 2.0 or Atom 1.0 syndication feeds, or consuming them, can be accomplished using the classes in the System.ServiceModel.Syndication namespace. Use the SyndicationFeed and SyndicationItem classes for modeling syndication feeds and their items and the Atom10FeedFormatter and Rss20FeedFormatter classes for rendering a SyndicationFeed object into the appropriate XML markup. Be sure to download the demo application. It shows how to create an ASP.NET page that emits either an RSS 2.0 or Atom 1.0 syndication feed, as well as how to consume and display another site's syndication feed.

Happy Programming!

References

About Scott Mitchell

Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott works as an independent consultant, tra...

This author has published 8 articles on DotNetSlackers. View other articles or the complete profile here.

Informations segmentTeknisk interesserede personer
Emnerweb