Laurent Kempé
RSS et Atom à l’aide du framework ASP.NET MVC
Nous allons voir comment utiliser ASP.NET MVC pour rendre un flux Rss ou Atom en toute simplicité depuis un contrôleur.
Par Laurent Kempé publié le 09/12/2009 à 21:53, lu 1813 fois,
Notre but est de pouvoir délivrer un flux RSS ou Atom. Il s’agit purement d’une représentation de données donc on peut tout à fait la comparer à du HTML. Partant de ce principe nous devrons retourner depuis notre contrôleur ASP.NET MVC un équivalent à ViewResult qui lui retourne du HTML. Hors ViewResult est juste une spécialisation de ActionResult pour le rendu HTML.
Il nous faut donc créer une classe qui implémente la classe de base abstraite ActionResult :

namespace System.Web.Mvc

{

    public abstract class ActionResult

    {

        public abstract void ExecuteResult(ControllerContext context);

    }

}

ActionResult ne contient qu’une seule méthode à surcharger cela devrait donc être relativement facile.
Pour cela nous créons une classe SyndicationResult héritant d’ActionResult, cette classe utilise la classe du .NET framework SyndicationFeedpour écrire soit le feed au format Rss, soit au format Atom :

using System;

using System.ServiceModel.Syndication;

using System.Text;

using System.Web.Mvc;

using System.Xml;

 

namespace RssMvcApplication.Web.Mvc

{

    ///<summary>

    /// Encapsulates the Syndication result of an action method and is used to perform a

    /// framework-level operation on the action method's behalf.

    ///</summary>

    public class SyndicationResult : ActionResult

    {

        private readonly SyndicationFeedFormatter _formatter;

        private const string RssContentType = "application/rss+xml";

        private const string AtomContentType = "application/atom+xml";

        private readonly string _contentType;

 

        ///<summary>

        /// Initializes a new instance of the <see cref="SyndicationResult"/> class.

        ///</summary>

        ///<param name="formatter"></param>

        public SyndicationResult(SyndicationFeedFormatter formatter)

        {

            if (formatter.Feed == null)

            {

                throw new ArgumentException("formatter parameter is not initialized with a feed.", "formatter");

            }

 

            if (formatter is Atom10FeedFormatter)

            {

                _contentType = AtomContentType;

            }

 

            if (formatter is Rss20FeedFormatter)

            {

                _contentType = RssContentType;

            }

 

            _formatter = formatter;

        }

 

        ///<summary>

        /// Enables processing of the result of an action method by a custom

        /// type that inherits from <see cref="T:System.Web.Mvc.ActionResult"/>.

        ///</summary>

        ///<param name="context">The context within which the result is executed.</param>

        public override void ExecuteResult(ControllerContext context)

        {

            context.HttpContext.Response.ContentType = _contentType;

 

            var ws = new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8, OmitXmlDeclaration = true };

 

            using (var writer = XmlWriter.Create(context.HttpContext.Response.Output, ws))

            {

                if (writer != null) _formatter.WriteTo(writer);

            }

        }

    }

}

Puis nous ajoutons dans la MasterPage Site.Master, deux ActionLink sur le contrôleur Home pour les méthodes Rss et Atom:

< ul id="menu">             

    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>

    <li><%= Html.ActionLink("About", "About", "Home")%></li>

    <li><%= Html.ActionLink("Rss", "Rss", "Home")%></li>

    <li><%= Html.ActionLink("Atom", "Atom", "Home")%></li>

</ ul >

Afin d’obtenir les deux liens :
 
/content/5ba4d6c2-da41-40f0-bdc5-fe80b6bbf1e9/image1.jpeg
 
Il ne nous reste plus qu’à utiliser notre nouvel ActionResult dans notre contrôleur Home afin de pouvoir répondre au click de l’utilisateur sur le lien Rss ou Atom. Pour cela nous ajoutons deux méthodes au contrôleur HomeController, Rss et Atom :

using System.Linq;

using System.ServiceModel.Syndication;

using System.Web.Mvc;

using RssMvcApplication.Domain;

using RssMvcApplication.Services;

using RssMvcApplication.Web.Mvc;

 

namespace RssMvcApplication.Controllers

{

    [HandleError]

    public class HomeController : Controller

    {

        private readonly SearchService _searchService;

 

        public HomeController()

        {

            _searchService = new SearchService();

        }

 

        public ActionResult Rss()

        {

            var syndicationFeed = GetSyndicationFeed();

 

            return new SyndicationResult(new Rss20FeedFormatter(syndicationFeed));

        }

 

        public ActionResult Atom()

        {

            var syndicationFeed = GetSyndicationFeed();

 

            return new SyndicationResult(new Atom10FeedFormatter(syndicationFeed));

        }

 

        private SyndicationFeed GetSyndicationFeed()

        {

            var results = _searchService.GetResults();

 

            return new SyndicationFeed

            {

                Title = new TextSyndicationContent(@"Tech Head Brothers"),

                Description = new TextSyndicationContent(@"Feed description"),

                Items = results.ToList().ConvertAll(result => result.ToSyndicationItem())

            };

        }

 

        public ActionResult Index()

        {

            ViewData["Message"] = "Welcome to ASP.NET MVC!";

 

            return View();

        }

 

        public ActionResult About()

        {

            return View();

        }

    }

}

HomeController utilise une couche de service fictive SearchService. SearchService n’est pas injecté dans le constructeur de HomeController pour des raisons de simplicité de l’exemple.

using System.Collections.Generic;

using System.Collections.ObjectModel;

using RssMvcApplication.Domain;

 

namespace RssMvcApplication.Services

{

    public class SearchService

    {

        public IEnumerable<Result> GetResults()

        {

            return new Collection<Result>

                       {

                           new Result {Title = "1ere Titre", Description = "Ceci est la description du 1er titre."},

                           new Result {Title = "2eme Titre", Description = "Ceci est la description du 2eme titre."}

                       };

        }

    }

}

La classe Result correspond à une classe du domaine de notre application et non à un Model dans la couche de visualisation ASP.NET MVC .

namespace RssMvcApplication.Domain

{

    public class Result

    {

        public string Title { get; set; }

        public string Description { get; set; }

    }

}

La représentation de la classe Result au niveau de la couche de visualisation est un SyndicationItem. Il nous faut donc convertir Result en SyndicationItem, pour cela on utilise une méthode d’extension :

using System;

using System.ServiceModel.Syndication;

 

namespace RssMvcApplication.Domain

{

    public static class Helpers

    {

        ///<summary>

        /// Convert Domain Result to a SyndicationItem.

        ///</summary>

        ///<param name="result">The result.</param>

        ///<returns></returns>

        public static SyndicationItem ToSyndicationItem(this Result result)

        {

            return new SyndicationItem(result.Title, result.Description, new Uri("http://www.techheadbrothers.com"));

        }

    }

}

!!! Attention nous avons utilisé une Uri en dur dans le code pour simplifier l’exemple !!!
Au final la méthode de notre contrôleur appel une couche de service qui nous retourne un ensemble de classes du domaine de notre application ; Result. Cette collection est convertie en une collection de SyndicationItem utilisée pour initialiser un SyndicationFeed. Le SyndicationFeed est lui-même utilisé soit par un Rss20FeedFormatter, soit par un Atom10FeedFormatter pour créer notre SyndicationResult.
Et voilà le résultat, lorsque l’on click sur le lien Rss :
 
/content/5ba4d6c2-da41-40f0-bdc5-fe80b6bbf1e9/image2.jpeg
 
 
» Démarrer une discussion