views:

1487

answers:

4

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.

+1  A: 

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:

http://www.doodle.co.uk/Albums/Rss.aspx?AlbumID=61

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:

http://www.doodle.co.uk/xsl/rssPhotos.xslt

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").

Zhaph - Ben Duguid
That seems like a lot of work given that the only thing the SyndicationFeed class lacks is the ability to set xmlns:media="http://search.yahoo.com/mrss" in the <rss> tag.
James
To be honest, I wrote that in .NET 2.0 before the syndication feed stuff came out. It's not all that much work ;)I guess with a different amount of work one could easily knock out at new SyndicationFeedFormatter that handles MRSS feeds, I've not yet looked into it that's all.
Zhaph - Ben Duguid
+1  A: 

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;
terfdaq
A: 

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

    }
chrisg
A: 

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.

http://mediarss.codeplex.com

Foovanadil