IN .NET 3.5 I know of the System.ServiceModel.Syndication classes which can create Atom 1.0 and RSS 2.0 rss feeds. Does anyone know of a way to easily generate yahoo's Media RSS in ASP.Net? I am looking for a free and fast way to generate an MRSS feed.
Step 1: Convert your data into XML:
So, given a List photos:
var photoXml = new XElement("photos",
new XElement("album",
new XAttribute("albumId", albumId),
new XAttribute("albumName", albumName),
new XAttribute("modified", DateTime.Now.ToUniversalTime().ToString("r")),
from p in photos
select
new XElement("photo",
new XElement("id", p.PhotoID),
new XElement("caption", p.Caption),
new XElement("tags", p.StringTags),
new XElement("albumId", p.AlbumID),
new XElement("albumName", p.AlbumName)
) // Close element photo
) // Close element album
);// Close element photos
Step 2: Run the XML through some XSLT:
Then using something like the following, run that through some XSLT, where xslPath is the path to your XSLT, current is the current HttpContext:
var xt = new XslCompiledTransform();
xt.Load(xslPath);
var ms = new MemoryStream();
if (null != current){
var xslArgs = new XsltArgumentList();
var xh = new XslHelpers(current);
xslArgs.AddExtensionObject("urn:xh", xh);
xt.Transform(photoXml.CreateNavigator(), xslArgs, ms);
} else {
xt.Transform(photoXml.CreateNavigator(), null, ms);
}
// Set the position to the beginning of the stream.
ms.Seek(0, SeekOrigin.Begin);
// Read the bytes from the stream.
var byteArray = new byte[ms.Length];
ms.Read(byteArray, 0, byteArray.Length);
// Decode the byte array into a char array
var uniEncoding = new UTF8Encoding();
var charArray = new char[uniEncoding.GetCharCount(
byteArray, 0, byteArray.Length)];
uniEncoding.GetDecoder().GetChars(
byteArray, 0, byteArray.Length, charArray, 0);
var sb = new StringBuilder();
sb.Append(charArray);
// Returns the XML as a string
return sb.ToString();
I have those two bits of code sitting in one method "BuildPhotoStream".
The class "XslHelpers" contains the following:
public class XslHelpers{
private readonly HttpContext current;
public XslHelpers(HttpContext currentContext){
current = currentContext;
}
public String ConvertDateTo822(string dateTime){
DateTime original = DateTime.Parse(dateTime);
return original.ToUniversalTime()
.ToString("ddd, dd MMM yyyy HH:mm:ss G\"M\"T");
}
public String ServerName(){
return current.Request.ServerVariables["Server_Name"];
}
}
This basically provides me with some nice formatting of dates that XSLT doens't give me.
Step 3: Render the resulting XML back to the client application:
"BuildPhotoStream" is called by "RenderHelpers.Photos" and "RenderHelpers.LatestPhotos", which are responsible for getting the photo details from the Linq2Sql objects, and they are called from an empty aspx page (I know now that this should really be an ASHX handler, I've just not gotten around to fixing it):
protected void Page_Load(object sender, EventArgs e)
{
Response.ContentType = "application/rss+xml";
ResponseEncoding = "UTF-8";
if (!string.IsNullOrEmpty(Request.QueryString["AlbumID"]))
{
Controls.Add(new LiteralControl(RenderHelpers
.Photos(Server.MapPath("/xsl/rssPhotos.xslt"), Context)));
}
else
{
Controls.Add(new LiteralControl(RenderHelpers
.LatestPhotos(Server.MapPath("/xsl/rssLatestPhotos.xslt"), Context)));
}
}
At the end of all that, I end up with this:
Which worked in Cooliris/PicLens when I set it up, however now seems to render the images in the reflection plane, and when you click on them, but not in the wall view :(
In case you missed it above, the XSLT can be found here:
You'll obviously need to edit it to suit your needs (and open it in something like Visual Studio - FF hides most of the stylesheet def, including xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss").
I was able to add the media namespace to the rss tag by doing the following:
XmlDocument feedDoc = new XmlDocument();
feedDoc.Load(new StringReader(xmlText));
XmlNode rssNode = feedDoc.DocumentElement;
// You cant directly set the attribute to anything other then then next line. So you have to set the attribute value on a seperate line.
XmlAttribute mediaAttribute = feedDoc.CreateAttribute("xmlns", "media", "http://www.w3.org/2000/xmlns/");
mediaAttribute.Value = "http://search.yahoo.com/mrss/";
rssNode.Attributes.Append(mediaAttribute);
return feedDoc.OuterXml;
Here a simplified solution I ended up using within a HttpHandler (ashx):
public void GenerateRss(HttpContext context, IEnumerable<Media> medias)
{
context.Response.ContentType = "application/rss+xml";
XNamespace media = "http://search.yahoo.com/mrss";
List<Media> videos2xml = medias.ToList();
XDocument rss = new XDocument(
new XElement("rss", new XAttribute("version", "2.0"),
new XElement("channel",
new XElement("title", ""),
new XElement("link", ""),
new XElement("description", ""),
new XElement("language", ""),
new XElement("pubDate", DateTime.Now.ToString("r")),
new XElement("generator", "XLinq"),
from v in videos2xml
select new XElement("item",
new XElement("title", v.Title.Trim()),
new XElement("link", "",
new XAttribute("rel", "alternate"),
new XAttribute("type", "text/html"),
new XAttribute("href", String.Format("/Details.aspx?vid={0}", v.ID))),
new XElement("id", NotNull(v.ID)),
new XElement("pubDate", v.PublishDate.Value.ToLongDateString()),
new XElement("description",
new XCData(String.Format("<a href='/Details.aspx?vid={1}'> <img src='/Images/ThumbnailHandler.ashx?vid={1}' align='left' width='120' height='90' style='border: 2px solid #B9D3FE;'/></a><p>{0}</p>", v.Description, v.ID))),
new XElement("author", NotNull(v.Owner)),
new XElement("link",
new XAttribute("rel", "enclosure"),
new XAttribute("href", String.Format("/Details.aspx?vid={0}", v.ID)),
new XAttribute("type", "video/wmv")),
new XElement(XName.Get("title", "http://search.yahoo.com/mrss"), v.Title.Trim()),
new XElement(XName.Get("thumbnail", "http://search.yahoo.com/mrss"), "",
new XAttribute("url", String.Format("/Images/ThumbnailHandler.ashx?vid={0}", v.ID)),
new XAttribute("width", "320"),
new XAttribute("height", "240")),
new XElement(XName.Get("content", "http://search.yahoo.com/mrss"), "a",
new XAttribute("url", String.Format("/Details.aspx?vid={0}", v.ID)),
new XAttribute("fileSize", Default(v.FileSize)),
new XAttribute("type", "video/wmv"),
new XAttribute("height", Default(v.Height)),
new XAttribute("width", Default(v.Width))
)
)
)
)
);
using (XmlWriter writer = new XmlTextWriter(context.Response.OutputStream, Encoding.UTF8))
{
try
{
rss.WriteTo(writer);
}
catch (Exception ex)
{
Log.LogError("VideoRss", "GenerateRss", ex);
}
}
}
Just to add another option for future reference:
I created a library that leverages the SyndicationFeed classes in .NET and allows you to read and write media rss feeds.