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();
}

}

By Jesper Lind

Integrera W3C Validation Service i dina projekt

När man tillhandahåller ett CMS-system åt en kund så är det nästan oundvikligt att kunderna kommer att skriva in ogiltig XHTML. Alla kan helt enkelt inte vara webbstandard-freaks och det är inget man kan kräva av någon.

Då skulle det vara perfekt om man kunde få en varning så fort ogiltig kod har publiserats, så man kan gå in och rätta till den.

Blitz Labs har gjort en sådan lösning och delar med sig av .NET-koden. Funktionen tar emot en url som ska kontrolleras. Skickar ett anrop till W3C Markup Validation Service. Tar emot resultatet genom deras SOAP-tjänst och transformerar det till RSS med hjälp av en XSLT-fil.

Prenumenera sedan på den RSS som skapats och få meddelande så fort någon ogiltig kod har publiserats.

By Jesper Lind

Skapa xml från filnamn i en mapp

Vi har tidigare visat ett koncept på hur man kan göra ett bildspel i flash med bildnamn som laddas från en xml-fil. Det är ett bra sätt så att man ska slippa att gå in i flash-filen och ändra varje gång man vill byta ut bilderna.

Vi använder den rätt ofta i våra egna projekt och hittills har vi sparat meta-data för bilderna i en databas. Det har sina fördelar ifall man vill spara bildtexter eller liknande.

Men det kan bli rätt omständigt att först göra en editor för att hantera bilduppladdingen. Därför skrev jag ett litet kodstycke i C# som kollar efter bilder i en angiven mapp, och skapar en xml-fil baserat på filnamnen.

I exemplet används två variabler som är sökvägar till xml- och bildmappar. Dessa läses i vårat fall in från Web.Config

//Här finns våra xml-filer
public static string strXmlRootPath = ConfigurationManager.AppSettings["XmlRootPath"];

//Här lagrar vi bilderna
public static string strMediaRootPath = ConfigurationManager.AppSettings["MediaRootPath"];

Funktionerna som skapar xml-filen

private void CreateSlideshow()
{
string strXMLPath = strXmlRootPath + "slideshow.xml";

if(File.Exists(strXMLPath))
{
DateTime dtLastWriteTime = Convert.ToDateTime( ""+File.GetLastWriteTime(strXMLPath) );
//Skapar bara en ny fil en gång varje timme
if( DateTime.Compare(DateTime.Now,dtLastWriteTime.AddMinutes(60))==1 )
{
CreateSlideshowXml();
}
}
else
{
CreateSlideshowXml();
}
}

public void CreateSlideshowXml()
{
try
{
string strXMLPath = strXmlRootPath + "slideshow.xml";
FileStream objFileStream = new FileStream(strXMLPath, FileMode.Create);
XmlTextWriter objXmlWriter = new XmlTextWriter(objFileStream, System.Text.Encoding.GetEncoding("utf-8"));//iso-8859-1
objXmlWriter.Formatting = Formatting.Indented;
objXmlWriter.WriteStartDocument();
objXmlWriter.WriteStartElement("images");

//Skapa array av alla filer i mappen för slideshow-bilder
String[] strFiles = Directory.GetFiles(strMediaRootPath + "slides/", "*");
string strFileName = string.Empty;
string strFullPath = string.Empty;

foreach (string strFile in strFiles)
{
strFileName = Path.GetFileName(strFile);
strFullPath = Path.GetFullPath(strFile);

objXmlWriter.WriteStartElement("pic");
//Url till bild
objXmlWriter.WriteStartElement("image");
objXmlWriter.WriteString(strMediaRootUrl + "slides/" + strFileName);
objXmlWriter.WriteEndElement();//Slut image
//Länk
objXmlWriter.WriteStartElement("link");
//Denna gång lämnar vi -link- tomt. Här kan man spara en url om bilderna ska vara klickbara
objXmlWriter.WriteEndElement();//Slut link

objXmlWriter.WriteEndElement();//Slut pic
}


objXmlWriter.WriteEndElement();//Slut images
objXmlWriter.WriteEndDocument();
objXmlWriter.Close();
}
catch (Exception objException)
{
Trace.Warn("XML-fil för slideshow kunde ej sparas! Fel: ",objException.Message);
}
}

Och slutligen spottas xml-filen ut som följer den här strukturen:

<?xml version="1.0" encoding="utf-8"?>
<images>
<pic>
<image>http://localhost:1643/test-site/media/slides/IMG_4954.jpg</image>
<link />
</pic>
<pic>
<image>http://localhost:1643/test-site/media/slides/IMG_4955.jpg</image>
<link />
</pic>
<pic>
<image>http://localhost:1643/test-site/media/slides/IMG_4956.jpg</image>
<link />
</pic>
<pic>
<image>http://localhost:1643/test-site/media/slides/IMG_4960.jpg</image>
<link />
</pic>
<pic>
<image>http://localhost:1643/test-site/media/slides/IMG_4961.jpg</image>
<link />
</pic>
</images>

 

By Jesper Lind

Slideshow i flash med dynamiskt inladdade bilder

Vi tänkte dela med oss med ett exempel på hur man kan göra en slideshow i flash. Längst ner i detta inlägg finns en länk där du kan ladda ner zip-fil med Fla-fil och ett exempel på XML-fil som används för att ladda in bilderna.

Filen kan konfigureras med två parametrar men i så fall måste två rader kommenteras bort i orginal-filen. Här är ett exempel på hur dessa parametrar som anger vilken XML-fil som ska användas och även hastigheten på hur snabbt bilderna ska bytas. Filerna är gjorda för bilder med storlek på 400 bredd och 265 pixlar i höjd. Hastigheten på bildväxlingen är satt till 4 sekunder i flash-filen.

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="400" height="265">
<param name="movie" value="slideshow.swf?albumURL=album-data.xml&time=4000" />
<param name="quality" value="high" />
<embed src="slideshow.swf?albumURL=album-data.xml&time=4000" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="400" height="265"></embed>
</object>

Det finns även möjlighet till att göra så att bilderna blir klickbara. Då måste följande rad kommenteras bort i actionscriptet på rad 7.

hit.enabled=false;

Strukturen på XML-filen ser ut så här.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<images>
<pic>
<image>http://www.codeodyssey.com/footprints/data/1.jpg</image>
<link>enter URL for click on image</link>
</pic>
<pic>
<image>http://www.codeodyssey.com/footprints/data/2.jpg</image>
<link>enter URL for click on image</link>
</pic>
</images>

Vill ni se ett exempel på en slideshow kan ni besöka myspace.com/clubfootprints. Instruktioner om hur man länkar in flashfiler på Myspace har vi skrivit om tidigare om det kan vara intressant. Rekommenderar även läsning om hur man gör så att flashfiler aktiveras med en gång i webbläsaren IE.

Vill ni använda denna slideshow i era egna projekt så är det fritt fram. Länka gärna till vår hemsida eller detta inlägg. Det uppskattas. Vi vill också passa på att tacka Fakepilot.com som har varit med och utvecklat dessa filer.

Ladda ner zip-fil med orginalfiler för slideshowen

By Jesper Lind

Sätt upp ett RSS-flöde

RSS står för Really Simple Syndication och är en XML-dialekt som följer XML 1.0-specifikationen. RSS är av de nya beståndsdelarna i den "nya webben" och har blivit väldigt populärt på senare tid. Användare kan med egna RSS-läsare, prenumenera på innehåll från en webbplats. Fördelen är enorm genom att man kan från en samlad plats se exakt vilka av ens favoritsajter som har skrivit något nytt. RSS skapar även möjligheten för olika nyhetssajter att publicera innehåll från en annan webbsida.

Jag använde artikeln "Skapa en RSS-feed för din webbplats" som inspiration. Jag skrev om den för att passa till ASP.NET C# samt att jag i mitt kodexempel skriver en fysisk xml fil direkt på hårddisken. I exemplet på Dileno.com läggs xml-filen i cache. Min funktion som skapar ett RSS-flöde av posterna i min blogg och ser ut ungefär så här.

//Funktion som skapar RSS flöde
protected void GenerateRss()
{
try
{

//Fysisk sökväg på servern (Byt ut mot den på din server)
string strXMLPath = "C:/ . . . /rss.xml";

FileStream objFileStream = new FileStream(strXMLPath,FileMode.Create);
XmlTextWriter xtw = new XmlTextWriter(objFileStream,System.Text.Encoding.GetEncoding("iso-8859-1"));
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 - expanderar webben");
xtw.WriteElementString("language","sv-SE");
xtw.WriteElementString("copyright","Copyright (c) 2004-2006 Code Odyssey");

OleDbConnection conn = new OleDbConnection (strConn);
bool boolPermission = false;
OleDbDataReader objDataReader=null;
try
{
string strSQL = "SELECT Blog.Id, Blog.Title, Blog.Body, Blog.PublishDate FROM Blog ORDER BY Blog.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","http://www." + strUrl.ToLower() + "/Blog.aspx_id=" + Id);
xtw.WriteElementString("guid","http://www." + strUrl.ToLower() + "/Blog.aspx_id=" + Id);
xtw.WriteElementString("description",Body);
xtw.WriteElementString("pubDate",PublishDate);
xtw.WriteEndElement();
}
objCommand.Dispose();
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
finally
{
if(objDataReader!=null)
{
objDataReader.Close();  
}
conn.Close();
}

//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);
}
}

Visa RSS för läsaren
Sen är det dags att lägga till en länk så att Firefox (och antagligen IE7) ska kunna se att din webbplats innehåller ett RSS-flöde och visa detta med den lilla RSS ikonen.

Denna tagg ser ut så här:

<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="xml/rss.xml" />

Vill man lägga till en länk till RSS från koden kan man göra så här:

//Lägg till RSS länk
HtmlLink link = new HtmlLink();
link.Attributes.Add("type", "application/rss+xml");
link.Attributes.Add("rel", "alternate");
link.Attributes.Add("href", "feed/rss.xml");
this.Page.Header.Controls.Add(link);

Bilder i RSS?
Först tänkte jag visa de bilder i mitt RSS-flöde men efter ha läst "RSS - bra eller dåligt?" så ångrade jag mig. Speciellt om man ska prenumenera på RSS genom en mobiltelefon så vill man ju inte ladda med en massa bilder i onödan.

Validera bloggen
Till sist är det dags att prova så att allt fungerar som det ska. Mozilla Thunderbirds inbyggda RSS läsare fungerar utmärkt till detta. Eller aktiva bokmärken i Firefox. Man bör även validera CSS-flödet, en valideringstjänst finns på Feedvalidator.org.

By Jesper Lind
1