Virtuellt RSS-flöde med .NET

Vi har tidigare har vi på bloggen visat hur man kan skapa en RSS-fil från poster i en databas.

Nu tänkte jag visa ett snarlikt exempel men här skriver vi flödet direkt till Response-strömmen istället för att skapa en fysisk fil. Kallar denna metoden, att leverera ett RSS-flöde "virtuellt", i brist på bättre term.

Hämtade lite inspiration från Dileno.com men använde istället min egen kod från tidigare exempel.

Själva ASPX-filen sparar jag som Rss.aspx och innehåller endast en rad kod.

<%@ Page Language="C#" Strict="False" Debug="True" Inherits="_Rss" CodeFile="Rss.aspx.cs" %>

I koden bakom hämtas posterna ur en tabell i en Access-databas. Bygger ihop en sträng med xml taggarna för RSS-definitionen och lägger sedan in den i cache. Detta för att det inte ska bli överbelastning ifall flödet anropas ofta.

using System;
using System.Data;
using System.Data.OleDb;
using System.Configuration;
using System.Text;
using System.Web;
using System.IO;
using System.Xml;

public partial class _Rss : System.Web.UI.Page
{
static string strConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
static string strRootUrl = "http://codeodyssey.se";

protected void Page_Load(object sender, EventArgs e)
{
Response.ContentType = "text/xml";
Response.ContentEncoding = Encoding.UTF8;
Response.Write(GetRssString());
}

//Kollar om det redan finns en sträng i cache, annars skapas en ny
protected string GetRssString()
{
string cacheName = "rss-feed";

//Hämta chachad data om det finns
if (Cache[cacheName] != null)
{
return Convert.ToString(Cache[cacheName]);
}
else
{
string newlyGeneratedRss = GenerateRss();
Cache.Insert(cacheName, newlyGeneratedRss, null, DateTime.Now.AddMinutes(20), TimeSpan.Zero);
return Convert.ToString(newlyGeneratedRss);
}
}

//Funktion som skapar en textSträng som innehåller rss-feed
protected string GenerateRss()
{
StringWriter sw = new StringWriter();
try
{

XmlTextWriter xtw = new XmlTextWriter(sw);//,System.Text.Encoding.GetEncoding("UTF-8")
xtw.Formatting = Formatting.Indented;
xtw.WriteStartDocument();

//skriv ut <rss version="2.0">
xtw.WriteStartElement("rss");
xtw.WriteAttributeString("version","2.0");

//skriv ut <channel>
xtw.WriteStartElement("channel");

//skriv ut element som tillhör <channel>
xtw.WriteElementString("title","Codeodyssey.se");
xtw.WriteElementString("link","http://www.codeodyssey.se/");
xtw.WriteElementString("description","Code Odyssey - gräver djupt i kodträsket");
xtw.WriteElementString("language","sv-SE");
xtw.WriteElementString("copyright","Copyright (c) 2004-2007 Code Odyssey");

OleDbConnection conn = new OleDbConnection (strConn);
bool boolPermission = false;
OleDbDataReader objDataReader=null;
try
{
string strSQL = "SELECT TOP 10 * FROM News WHERE Published=true ORDER BY PublishDate DESC";

conn.Open();

OleDbCommand objCommand = new OleDbCommand(strSQL, conn);
objDataReader = objCommand.ExecuteReader();
while (objDataReader.Read() == true)
{
int Id = Convert.ToInt32(objDataReader["Id"]);
string Title = Convert.ToString(objDataReader["Title"]);
string Body= Convert.ToString(objDataReader["Body"]);
//Se till att datum följer RFC-822 standard
string PublishDate = Convert.ToString( ((DateTime)objDataReader["PublishDate "]).ToString("r"));


//skriv ut <item> och dess innehåll
xtw.WriteStartElement("item");
xtw.WriteElementString("title",Title);
xtw.WriteElementString("link", strRootUrl.ToLower() + "/news.aspx?id=" + Id);
xtw.WriteElementString("guid", strRootUrl.ToLower() + "/news.aspx?id=" + Id);
xtw.WriteElementString("description",Body);
xtw.WriteElementString("pubDate",PublishDate);
xtw.WriteEndElement();
}
objCommand.Dispose();
objCommand = null;
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
finally
{
if(objDataReader!=null)
{
objDataReader.Close();
objDataReader = null;
}
if(conn!=null)
{
conn.Close();
conn = null;
}
}

//skriv ut </channel>
xtw.WriteEndElement();

//skriv ut </rss>
xtw.WriteEndElement();

//Stäng xml skrivaren
xtw.Close();
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
return sw.ToString();
}

}

Comments

Tack för en allmänt bra blogg :) För just denna artikel tänkte jag komma med lite Tips: Sätt contenttype mm i page-deklarationen ex: <%@ Page Language="C#" Inherits="_Rss" CodeFile="Rss.aspx.cs" ContentType="text/xml" EnableViewState="false" EnableSessionState="false" %> (slå av viewstate och sessionstate för att de inte behövs och det optimerar sidan) ... mer generella liknande tips: http://www.codeproject.com/useritems/aspdotnetoptimization.asp"> http://www.codeproject.com/useritems/aspdotnetoptimization.asp Och när vi använder aspx:en's konfigurationsinställningar istället för kod så varför inte använda denna till catch:ning med? <%@ OutputCache Duration="1200" VaryByParam="none"%> Pageklassen är specialiserad för att skapa websidor. Den sköter httprequest för just websidor. Är det en annan typ av httprequest än för en sida kan man istället använda en webhandler (.ashx) Bra guide på för att skapa en webhandler för RSS-bruk: http://www.aspcode.net/articles/l_en-us/t_default/asp.net/creating-an-ashx-handler-in-asp.net_article_275.aspx"> http://www.aspcode.net/articles/l_en-us/t_default/asp.net/creating-an-ashx-handler-in-asp.net_article_275.aspx Ytterligare tips är ett färdigt kodbibliotek för RSS-strömmar (för att slippa skriva repetetiv kod) http://www.codeplex.com/aspnetrsstoolkit/"> http://www.codeplex.com/aspnetrsstoolkit/ Där finns möjlighet att använda både generisk klass för RSS "GenericRssHttpHandlerBase" och möjlighet till starkt typade klasser för sina RSS-strömmar m.h.a build providers ( Släpp mallfilen i App_Code och providern autogenererar en klass med värden och medlemmar baserat från filen.
Jätteroligt att du gillar bloggen och tack för de suveräna tipsen. Jag ska ta och skriva om exemplet enligt dina förslag i ett kommande inlägg. Jag har sneglat lite på RSS Toolkit men inte provat det än. Ska definitivt kolla vidare på det vid tillfälle.