William Duffy

Glasgow Based C# ASP.NET Web Developer

RssResult – An ASP.NET MVC RSS ActionResult

One of the most common tasks for data serving websites is offering an RSS feed that users can subscribe to in order to keep up with the latest updates to that data.

Previously I posted the article Creating a simple RSS feed using ASP.NET MVC which demonstrated how to create an RSS feed in a quick, easy way. Here, I will show you how to create an RssResult to be returned directly from your controller. This offers a much more scalable, reusable approach that is flexible enough to handle any data that you wish to serve and is designed specifically for addition to your ASP.NET MVC stack.

The RssResult must be capable of taking any data and knowing how to render an RSS item from it (i.e. news, events, posts, comments, reviews etc). So before we create the RssResult we need to abstract the structure of an RSS item. We do this by creating an interface abstraction to accommodate this. Any object that is to be served can implement this interface allowing the RssResult to work with it.

1
2
3
4
5
6
7
8
9
namespace System
{
    public interface IRss
    {
        string Title { get; }
        string Description { get; }
        string Link { get; }
    }
}

The standard return type of a controller’s methods is the abstract type ActionResult. In most cases the actual returned object will be of type ViewResult, which will look for a view to use when rendering your model to the response stream. Here, our RssResult will inherit from ActionResult, just as ViewResult does, but will internally render its own XML output and alter the response’s content-type header to xml, avoiding any view files or extra work in the controller. Using dependency injection the RssResult will not be instantiable without being supplied with the data it has to serve, which will be a List. It will also accept a title and description for the feed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Collections.Generic;
using System.Xml;
 
namespace System.Web.Mvc
{
    public class RssResult : ActionResult
    {
 
        private List<IRss> _items;
        private string _title;
        private string _description;
 
        /// <summary>
        /// Initialises the RssResult
        /// </summary>
        /// <param name="items">The items to be added to the rss feed.</param>
        /// <param name="title">The title of the rss feed.</param>
        /// <param name="description">A short description about the rss feed.</param>
        public RssResult(IEnumerable<IRss> items, string title, string description)
        {
            _items = new List<IRss>(items);
            _title = title;
            _description = description;
        }
 
        public override void ExecuteResult(ControllerContext context)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.NewLineHandling = NewLineHandling.Entitize;
 
            context.HttpContext.Response.ContentType = "text/xml";
            using (XmlWriter _writer = XmlWriter.Create(context.HttpContext.Response.OutputStream, settings))
            {
 
                // Begin structure
                _writer.WriteStartElement("rss");
                _writer.WriteAttributeString("version", "2.0");
                _writer.WriteStartElement("channel");
 
                _writer.WriteElementString("title", _title);
                _writer.WriteElementString("description", _description);
                _writer.WriteElementString("link", context.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority));
 
                // Individual items
                _items.ForEach(x =>
                {
                    _writer.WriteStartElement("item");
                    _writer.WriteElementString("title", x.Title);
                    _writer.WriteElementString("description", x.Description);
                    _writer.WriteElementString("link", context.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority) + x.Link);
                    _writer.WriteEndElement();
                });
 
                // End structure
                _writer.WriteEndElement();
                _writer.WriteEndElement();
            }            
        }
 
    }
}

As you can see above, the RssResult itself is pretty simple. It takes the collection of IRss items in it’s constructor. By inheriting the abstract type ActionResult it must override ExecuteResult which is called by the framework when it is returned from the controller, which you can see an example of below. One thing to notice in the following code snippet is that the original list of items must be cast to a list of IRss. This is due to the limitations of covariance and contravariance on generics in the C# language. Future versions may support this so that casting will not be required.

1
2
3
4
5
public ActionResult Feed()
        {
            IEnumerable<IRss> news = new NewsService().GetByLatest().Cast<IRss>();
            return new RssResult(news, "William Duffy - Glasgow Based ASP.NET Web Developer", "The latest news on ASP.NET, C# and ASP.NET MVC ");
        }

What is NewsService?

A few people have asked what NewsService is, how does it work and if they could have some sample code. Whenever I model software I separate entities, business logic and data access into their own architectural layers. Basically, NewService.GetByLatest() is in the business logic layer, which calls the data access layer and asks for all the latest news items. I’ve put together a quick and dirty example below for you to get started with. Notice that the data access layer is internal. Final versions would refactor the ADO.NET code, entity mappings etc into reusable blocks.

 
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
 
public class News : IRss
{
    public Guid ID { get; set; }
    public string Title { get; set; }
    public string Preview { get; set; }
    public string Body { get; set; }
    public DateTime DateCreated { get; set; }
 
    #region IRss Members
 
    public string IRss.Title { get { return Title  ;} }
    public string IRss.Description { get { return Preview ;} }
    public string IRss.Link { get { return string.Format("http://www.wduffy.co.uk/news/view.aspx?id={0}", ID); } }
 
    #endregion
}
 
public class NewsService
{
    public List<News> GetByLatest()
    {
        // Do business logic stuff here if required
        return new NewsData().GetByLatest();
    }
}
 
internal class NewsData
{
    public List<News> GetByLatest()
    {
        var result = new List<News>();
 
        using (var conn = new SqlConnection("Your Connection String"))
        {
            var cmd = new SqlCommand("Select TOP 5 ID, Title, Preview, Body, DateCreated FROM tblNews ORDER BY DateCreated DESC", conn);
            conn.Open();
 
            using (var reader = cmd.ExecuteReader())
                while (reader.Read())
                {
                    var news = new News();
                    news.ID = reader.GetGuid(0);
                    news.Title = reader.GetString(1);
                    news.Preview = reader.GetString(2);
                    news.Body = reader.GetString(3);
                    news.DateCreated = reader.GetDateTime(4);
 
                    result.Add(news);
                }
        }
 
        return result;
    }
}

Tagged as , , , , , , + Categorized as ASP.NET, C#, MVC

19 Comments

  1. Another quality post by Mr Duffy! You don’t actually work do you?

    Yeah it does annoy me slightly that you have to do a .Cast() to get things to be “smaller” when in actual fact the compiler could do that automatically, and truthfully by using an interface it should know that your object can “fit” even if it does lose the other properties that aren’t part of the interface.

    Being the optimist that I am, I love to make things faster (optimists optimization see what I did there?). We found an amazing tool a while back that would take a DataReader and an SQL result and apply the SQL result to an object without further mapping code. If the SQL result didn’t contain a field name matching a property of the object, that property wouldn’t be mapped.

    So you could do a cheap SQL statement like “SELECT Title, Description, Link FROM MyTable;” and using an object instead of interfaces:

    public class RssItem
    {
    // properties
    }

    the generic reader could then be called and map things up for you. So a method like:

    List news = new NewsService().GetByLatestForRss();

    would save the .Cast() each time the feed was hit. But then you could start .net Caching, and then any performance gain (if its that much) gained from the extra work I needed to put in to build the smaller classes (or views as I likes to call them, if you go down the psuedo-SQL naming convention) to avoid the .Cast would be lost.

    Pah! So many ways to do things. William you always find the cleaner route!

  2. That is deeply flawed. Now the controller is responsible for picking the rendering type. Not good at all.

  3. Did you even read the post Brad? I would assume not from your “deeply flawed” comment. The controller is in control of which view to return, in this case returning an RssResult, which inherits ActionResult, just like returning a ViewResult. This RssResult is responsible for rendering the output to the client using the model, not the controller. The controller has no knowledge whatsoever about the view result, and at no point sets the render type. This is the exact behaviour specified by the MVC pattern.

  4. Nice post but still not advanced enough for a real rss feed like added logic for the modified since http header, partial updates and xtag support.

    But its a nice beginning.

  5. Thanks Ramon, there are definitely areas which could improve the Action, some of which you pointed out.

  6. I like this post very much, i will search so many pages for checking rssresult.

    This post is very useful for me, i will use it on my site.

  7. @Brad

    Clearly you have 0 knowledge of the MVC pattern.

    “The controller receives input and initiates a response by making calls on model objects.”
    source – http://en.wikipedia.org/wiki/Model-view-controller

    What William has implemented is 100% correct!

    His controller receives input, makes a call to retrieve his model, and then passes it down to the view.

    Complete S.O.C, that’s separation of concerns Brad (try to keep up), between the Model, View and Controller.

    So if you would get your head out of Web Forms for 5 minutes, you might actually learn something new! – but I’m sure you must be very happy in your drag and drop world :-)

    Anyway,

    Good stuff William

    Any more of this and Ill have you developing in Ruby on Rails next!

    Ninja

  8. what is NewsService in above code?

  9. Hi John, NewsService is an object in my business logic layer whch returns a collection of news items. Your codebase will need to implement this part of the code as it will be unique to your own domain model.

  10. can i get an example how to implement NewService() obj … im new to mvc

  11. Thank you for this post… We are in the progress of implementing your RssResults solution into our website http://www.citygenius.com

    Oliver

  12. hi william, can i plz get sample code of newsService()

  13. @John @aR I’ve updated the post with an example of NewsService. Hope this helps.

  14. @William : tnx for the update, it was a very useful for me …

Trackbacks & Pingbacks

  1. ASP.NET MVC Archived Blog Posts, Page 1

    [...] to VoteRssResult – An ASP.NET MVC RSS ActionResult (10/21/2009)Wednesday, October 21, 2009 from http://www.wduffy.co.ukPreviously I posted the article Creating a simple [...]

  2. ASP.NET MVC Archived Buzz, Page 1

    [...] to Vote[FriendFeed] RssResult – An ASP.NET MVC RSS ActionResult | William Duffy (11/25/2009)Wednesday, November 25, 2009 from [...]

  3. 9eFish

    RssResult – An ASP.NET MVC RSS ActionResult | William Duffy…

    9efish.感谢你的文章 – Trackback from 9eFish…

  4. links for 2009-12-28 « 2LeggedSpider

    [...] RssResult – An ASP.NET MVC RSS ActionResult | William Duffy (tags: aspnetmvc) [...]

  5. REST in ASP.NET MVC – Generating XML « Konczuras's Blog

    [...] without any duplication. The obvious way was to subclass ActionResult. After some inspiration from William Duffy’s RSSResult implementation, I came up with the following [...]

Leave a Reply