Jag bloggar numera på http://blog.dileno.com ».

Skapa en RSS-feed för din webbplats

en ASP.NET-artikel av Martin S., publicerad den 21 juni 2005
RSS är ett format som på senare tiden blommat upp rejält. Tack vare RSS finns möjligheten att låta användare prenumerera på innehåll på en webbplats. Jag visar hur du med hjälp av ASP.NET kan skapa en RSS-feed som dina besökare kan använda för att få reda på när du har uppdaterat din webbplats.

Kort om RSS


RSS står för Really Simple Syndication och är en XML-dialekt som följer XML 1.0-specifikationen. Formatet har till största del utformats av Netscape (RSS 0.9) och UserLand Software (RSS 0.91 och 2.0).

För att kunna läsa RSS-filer så behövs det en RSS-läsare. Det finns ett urval av dessa och bland de bättre är RSSOwl men jag använder själv e-postklienten Thunderbirds inbyggda RSS-läsare.

Fler RSS-läsare hittar du här: RSS Readers.

Använda XmlTextWriter för att skriva ut XML-data


Vi ska ha en sida, rss.aspx, där vi skriver ut alla RSS-element och information i dem. Det enda som behövs i rss.aspx är en rad kod:

<%@ Page Language="VB" Strict="False" Debug="True" Inherits="rss" Src="rss.vb" %>
Det viktiga är i stället codebehind - det som finns i rss.vb.

Tanken med detta script är att information ska hämtas från en databas och sedan genereras på rss.aspx. Till detta behöver vi importera ett antal namnområden, varav System.Data.OleDb, System.Data.IO och System.Xml är de viktigaste. Det här är namnområdena som behövs importeras:

Imports System
Imports System.Data
Imports System.Data.OleDb
Imports System.IO
Imports System.Text
Imports System.Text.Encoding
Imports Microsoft.VisualBasic
Imports System.Web
Imports System.Web.Caching
Imports System.Web.UI
Imports System.Web.UI.Page
Imports System.Xml

I proceduren page_load (som alltid körs när man laddar en sida) har vi sedan själva funktionaliteten. Eftersom det är ett XML-dokument vi ska skapa så måste vi sätta mime-typen till text/xml och teckenkodningen till förslagsvis UTF-8:

response.ContentType = "text/xml"
response.ContentEncoding = Encoding.UTF8

Vi behöver sedan skapa en StringWriter och en XmlTextWriter. StringWriter:n behövs för att skriva ut XML-datan på sidan och XmlTextWriter använder vi för att skapa själva XML-elementen.

dim sw as StringWriter = new StringWriter()
dim rw as XmlTextWriter = new XmlTextWriter(sw)

För att skriva ut de element som behövs i RSS-feeden använder vi oss sedan av metoderna WriteStartElement(), WriteAttributeString() och WriteElementString(). Nedan är huvudet i feeden:

'skriv ut <rss version="2.0">
rw.WriteStartElement("rss")
rw.WriteAttributeString("version","2.0")

'skriv ut <channel>
rw.WriteStartElement("channel")

'skriv ut element som tillhör <channel>
rw.WriteElementString("title","Dileno.com")
rw.WriteElementString("link","http://www.dileno.com/")
rw.WriteElementString("description","Dileno - en sajt som fokuserar på intervjuer, artiklar och foto.")
rw.WriteElementString("language","sv-se")
rw.WriteElementString("copyright","Copyright (c) 2001-2005 Dileno")

Detta genererar följande utdata:

<rss version="2.0">
<channel>
<title>Dileno.com</title>
<link>http://www.dileno.com/</link>
<description>Dileno - en sajt som fokuserar på intervjuer, artiklar och foto.</description>
<language>sv-se</language>
<copyright>Copyright (c) 2001-2005 Dileno</copyright>

Själva innehållet i RSS-feeden plockar vi ut från en databas och lägger sedan till så många poster vi vill:

'plocka ut info från databas för att skriva ut i RSS-feeden
dim SQL as string = "SELECT top 15 nId,nTitle,nText,nDate FROM tbl ORDER BY nId DESC"
dim Cn as new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;data source=" & Server.MapPath("db.mdb"))
dim Cm as new OleDbCommand(SQL,Cn)
dim dbRead as OleDbDataReader
Cn.Open()
dbRead = Cm.ExecuteReader()

'loopa genom innehållet som ska plockas ut
while dbRead.Read()

'skriv ut <item> och dess innehåll
rw.WriteStartElement("item")
rw.WriteElementString("title",dbRead.Item(1))
rw.WriteElementString("link","http://www.dileno.com/default.aspx?CatId=4" & "&ArtId=" & dbRead.Item(0))
rw.WriteElementString("description",replace(dbRead.Item(2),vbcrlf,"<br />"))
rw.WriteElementString("pubDate",cDate(dbRead.Item(3)).toString("F"))
rw.WriteEndElement()

end while

dbRead.Close()

'skriv ut </channel>
rw.WriteEndElement()

'skriv ut </rss>
rw.WriteEndElement()

rw.Close()

response.write(sw.toString())
sw.Close()

Först plockar vi alltså ut information från en databas. Sedan loopar vi igenom det vi plockar ut och lägger till i XmlTextWriter:n. Det är <item> som är starttaggen för respektive post i RSS-feeden. Vi lägger till en titel (title), länk till inlägget på webbplatsen (link), en beskrivning av innehållet i länken (description) och publiceringsdatum för inlägget (pubDate).

För att komma åt värdet för respektive kolumn i databasen använder jag mig av dbRead.Item(ett index) där 0 är nId, 1 är nTitle, 2 är nText och 3 är nDate.

Vi stänger elementen som är öppna (channel och rss), stänger XmlTextWriter:n och skriver ut innehållet som finns i StringWriter:n. Slutligen stänger vi också StringWriter:n.

Hur många poster som visas i RSS-feeden beror på hur många man plockar ut från databasen (15 i detta fall). Du får även byta ut namnen på kolumnerna i databasen så att det passar din databas.

Att cacha data i ASP.NET


En RSS-feed kan bli väldigt populär och att köra ovanstående kod varje gång någon väljer att läsa RSS-feeden kan i slutändan vara olyckligt – servern får väldigt mycket att göra och det drar mycket bandbredd. Lösningen i så fall kan vara att cacha RSS-feeden så att servern inte behöver arbeta lika mycket varje gång någon läser feeden.

Caching i .NET är ganska enkelt och med några rader kod kan vi cacha vår RSS-feed för snabbare åtkomst:

if Cache.Get(“rss-feed") is nothing then
Cache.Insert("rss-feed", sw.toString(), nothing, DateTime.Now.AddHours(1), TimeSpan.Zero)
else
response.write(cache("rss-feed"))
end if

Först kollar vi om det finns en cache för det vi vill skriva ut på sidan. Om det inte finns någon cachenyckel som heter rss-feed så skapar vi en sådan. Med sw.toString() talar vi om vad vi ska cacha, det vill säga det som finns i StringWriter:n (alltså själva XML-datan). nothing är ett CacheDependecy-värde som talar om ifall om cachingen ska bero på något – till exempel om en fil ändras och vad som ska hända med cachingen då. Med nothing talar vi om att cachingen inte ska bry sig om ifall om en fil ändras.
Om du använder C# så är null det värde du ska använda om du inte vill att cachingen ska bero på något.
DateTime.Now.AddHours(1) talar om att cachingen ska vara giltig i en timme från det att den ändrades senast, och med TimeSpan.Zero talar vi om att cachingen inte ska upphöra om ingen använder RSS-feeden. Vill du till exempel att cachingen ska upphöra efter 10 minuter om ingen använt RSS-feeden skriver du DateTime.Now(), TimeSpan.FromMinutes(10), TimeSpan.Zero i stället.

Om cachenyckeln rss-feed redan finns så skriver vi bara ut den.

Det finns dock ett problem med denna caching – lägger du till en ny post i databasen syns den inte på grund av cachingen. I så fall är en lösning att ta bort cachenyckeln rss-feed när du lagt till en ny post i databasen och sedan låta nästa läsare av RSS-feeden läsa en ocachad version av feeden. Du plockar bort en cachenyckel så här:

Cache.Remove("rss-feed")

Kodlistning rss.vb


Codebehindfilen rss.vb ser i sin helhet ut så här:

Imports System
Imports System.Data
Imports System.Data.OleDb
Imports System.IO
Imports System.Text
Imports System.Text.Encoding
Imports Microsoft.VisualBasic
Imports System.Web
Imports System.Web.Caching
Imports System.Web.UI
Imports System.Web.UI.Page


public class rss : inherits Page

sub page_load(sender as object, e as eventargs)

response.ContentType = "text/xml"
response.ContentEncoding = Encoding.UTF8

dim sw as StringWriter = new StringWriter()
dim rw as XmlTextWriter = new XmlTextWriter(sw)


'skriv ut <rss version="2.0">
rw.WriteStartElement("rss")
rw.WriteAttributeString("version","2.0")

'skriv ut <channel>
rw.WriteStartElement("channel")

'skriv ut element som tillhör <channel>
rw.WriteElementString("title","Dileno.com")
rw.WriteElementString("link","http://www.dileno.com/")
rw.WriteElementString("description","Dileno - en sajt som fokuserar på intervjuer, artiklar och foto.")
rw.WriteElementString("language","sv-se")
rw.WriteElementString("copyright","Copyright (c) 2001-2005 Dileno")


'plocka ut info från databas för att skriva ut i RSS-feeden
dim SQL as string = "SELECT top 15 nId,nTitle,nText,nDate FROM tbl ORDER BY nId DESC"
dim Cn as new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;data source=" & Server.MapPath("db.mdb"))
dim Cm as new OleDbCommand(SQL,Cn)
dim dbRead as OleDbDataReader
Cn.Open()
dbRead = Cm.ExecuteReader()

'loopa genom innehållet som ska plockas ut
while dbRead.Read()

'skriv ut <item> och dess innehåll
rw.WriteStartElement("item")
rw.WriteElementString("title",dbRead.Item(1))
rw.WriteElementString("link","http://www.dileno.com/default.aspx?CatId=4" & "&ArtId=" & dbRead.Item(0))
rw.WriteElementString("description",replace(dbRead.Item(2),vbcrlf,"<br />"))
rw.WriteElementString("pubDate",cDate(dbRead.Item(3)).toString("F"))
rw.WriteEndElement()

end while

dbRead.Close()

'skriv ut </channel>
rw.WriteEndElement()

'skriv ut </rss>
rw.WriteEndElement()

rw.Close()

if cache.get("rss-feed") is nothing then
Cache.Insert("rss-feed", sw.toString(), nothing, DateTime.Now.AddHours(1), TimeSpan.Zero)
else
response.write(cache("rss-feed"))
end if

sw.Close()

end sub

end class

Ladda ner exempelfilerna


Du kan ladda ner rss.aspx och rss.vb här: Ladda ner exempelfiler. (zip-fil, 1.31 kb)