Minimum Viable Product - Part 8 - RSS

Long live RSS (maybe)!

A few short years ago before Google killed off its reader, RSS feeds were ubiquitous on most websites. When building the first edition of my blog, I neglected to add an RSS feed and I was asked if I were planning on adding a feed.

After reading that, I did some googling to determine whether or not RSS feeds were in fact dead. After determining that RSS is still in use by some today, I decided that it wouldn't take much effort to add one to my blog and so this article was born. While RSS feeds might kill some of my traffic, it might also bring some new eyeballs to the screen. So rather than debate RSS feeds, let's just make one :)

All we need is bread and butter with a touch of cinnamon

Building an RSS feed won't be much trouble, we'll need three main ingredients:

  • A document type for the RSS feed (bread)
  • A template for the feed (butter)
  • A way to set the `text/xml` header (the cinnamon)

I'm going to assume you can create your document type without my help, it won't have any properties on it. I called mine RssPage. Next we'll take a peek at the RSS specification and put together a template for our new document type:

@using KGLLC.Umbraco.Helpers
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    var blogsFolder = Umbraco.TypedContentAtRoot().First().Children.First(x => x.DocumentTypeAlias == "BlogsFolder");
}<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
    <channel>
        <title>Kevin Giszewski Developer/Blogger</title>
        <link>http://kevin.giszewski.com</link>
        <description>The ramblings of Kevin Giszewski. Usually about .NET, Umbraco, filmmaking and other random tech stuff.</description>
        @foreach (var article in blogsFolder.Descendants("BlogPostPage").OrderByDescending(x => x.ToPublishedDate()))
        {   
            var tease = article.GetPropertyValue<string>("teaseDescription");

            <item>
                <title>@article.Name</title>
                @Html.Raw("<link>")@article.UrlAbsolute()@Html.Raw("</link>")
                <description>@tease.StripHtml()</description>
                <pubDate>@article.ToPublishedDate().ToString("r")</pubDate>
            </item>
        }
    </channel>
</rss>

So far we're not seeing anything remarkable in the code. We're just outputting Umbraco content in an RSS format. If you create a page of this type and visit it, you'll see your browser interprets this incorrectly as `text/plain` instead of `text/xml`. So what are we do to?

There's probably a few ways to do this, but the first thing that comes to mind is hijacking the document type.

Hijacking in Umbraco will (likely) not get you on a no-fly list

Hijacking is a buzz term in Umbraco and I feel the need to explain what it is and why you need to know about it. Take for example a brand new Umbraco developer. They create their document types, data types, templates and after a save/publish they get their page to stand before them. It's quite an amazing thing because there is a lot going on behind the scenes. A simplified published page request works like this:

  1. Umbraco looks at the URL
  2. A global controller is instantiated
  3. The controller grabs the model based on the URL
  4. The controller renders the view based on the configured template with the model
  5. Smiles all around, rinse and repeat

At its most basic level, we have a classic MVC pattern executing the request. What makes development move along in Umbraco quickly is the idea that you don't have to create a new controller (i.e. LoginController, FileController, FooController) well... ever! You really only need to focus on the model (document/data types) and the view (templates).

Ninety percent of the time, you will love the idea of only focusing on the model and views. However every now and again (10%) you'll need to roll up your sleeves and handle something at the controller level. In Umbraco this means overriding (hijacking) the global controller for just a specific use case.

You can hijack by document type or by template. In our case we'll be hijacking by document type as you can see in the code below:

using System.Web.Mvc;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;

namespace KGLLC.Umbraco.Controllers
{
    public class RssPageController : RenderMvcController
    {
        public override ActionResult Index(RenderModel model)
        {
            Response.AddHeader("content-type", "text/xml");

            return View("~/Views/RssPage.cshtml", model);
        }
    }
}

Let's break down our code a bit. You can see the class inherits from `RenderMvcController` which is the global controller class type. The name of our controller is important and should be named as '{document-type-name}Controller'. If you've never built a non-Umbraco .NET MVC site, you may not know that it controllers are named in a similar fashion — convention over configuration as they say.

Side note: One thing that really helped me understand where .NET MVC and Umbraco begin/end, I recommend this book. A lot of things will look familiar and will help you understand how Umbraco coexists with MVC.

We need to override the `Index` method as you see and set the header to use `text/xml` rather than the default of `text/plain`. Once you build that and revisit your page, it should now look like a properly formatted RSS feed.

Summary

While we got to implement an RSS feed, the real pearl of wisdom is the fact that Umbraco does a lot for you automatically and there are ways to override the default behaviors. We are now ready to transition to hosting our new blog on Azure in the next part. I'll leave you with the following video that I feel best represents the current state of RSS feeds: