Exposer un flux RSS/Atom avec MVC
Voici le dernier article sur ma série dédiée à la mise à disposition de flux RSS/Atom. Arpès Web API, attaquons la version MVC.
Un flux RSS ou Atom a pour vocation de retourner des informations à des clients qui ne formalise pas foncement toujours bien ce qu’il attend. La plus pars du temps, le client fait un simple Get sur une url fixe sans arguments et sens stipuler le format attendu. MVC est donc tout indiqué pour ce type d’opération.
Les plus anciens préfèreront le bon vieux Handler (ashx) ou la page aspx. Les rares vrais connaisseurs de WCF préfèreront utiliser son contrat dédié…. Il y en a pour tout les goûts. La solution MVC n’est donc pas la seule solution viable et simple. MVC étant pour autant de plus en plus utilisé, il semble bon de monter ce que l’on peut faire avec.
Comme pour la solution Web API, la version MVC est en deux parties :
- Un
Controller
qui va répondre aux requêtes et retourner une instance deSyndicationFeed
(la classe intégrée à .net Framework) - Un
ActionResult
qui va se charger de formater leSyndicationFeed
en XML respectant les formats RSS et Atom.
Pour simplifier mon code, j’ai réalisé une méthode statique qui me retourne une instance de SyndicationFeed
. La classe est fortement liée à ma couche de donnée. Je la présente ici uniquement pour mettre en avant les éléments qui sont utiles pour avoir une instance de SyndicationFeed
exploitable.
/// <summary>
/// Blog Feed (for RSS or ATOM)
/// </summary>
public sealed class FeedService
{
/// <summary>
/// Get the blog feed
/// </summary>
/// <returns></returns>
public static SyndicationFeed Get()
{
SyndicationFeed feed = new SyndicationFeed(
Settings.Current.Title,
Settings.Current.SubTitle,
new Uri(Settings.Current.Url));
using (var db = new DataService())
{
var posts = db.GetPosts(0, 10);
if (posts != null && posts.Length > 0)
{
// Create a new list of items
var items = posts.Select(c =>
new SyndicationItem(
c.Title,
new TextSyndicationContent(
c.HtmlSummary,
TextSyndicationContentKind.XHtml),
new Uri(c.Url),
c.Id.ToString(),
c.DateCreatedGmt)
).ToArray();
// Add items
feed.Items = items;
}
}
return feed;
}
}
Ce code permet d’avoir un Controller très simple. Celui-ci a 3 actions :
- Pour retourner le flux au format RSS par défaut lors de l’appel de l’url
/Feed
- Pour retourner le flux au format RSS lors de l’appel de l’url
/Feed/Rss
- Pour retourner le flux au format Atom lors de l’appel de l’url
/Feed/Atom
.
public class FeedController : Controller
{
public ActionResult Index()
{
return new FeedResult(FeedService.Get(), FeedResult.Type.Rss);
}
public ActionResult Atom()
{
return new FeedResult(FeedService.Get(), FeedResult.Type.Atom);
}
public ActionResult Rss()
{
return new FeedResult(FeedService.Get(), FeedResult.Type.Rss);
}
}
Côté ActionResult
, j’utilise les formatters Atom10FeedFormatter
et Rss20FeedFormatter
. Le code résultant est donc des plus simples.
public sealed class FeedResult : ActionResult
{
#region Declarations
private const String AtomContentType = "application/atom+xml";
private const String RssContentType= "application/rss+xml";
public enum Type
{
Atom,
Rss
}
private readonly SyndicationFeed _feed;
private readonly Type _type;
#endregion
#region Constructors
/// <summary>
/// Constructor
/// </summary>
/// <param name="feed"></param>
public FeedResult(SyndicationFeed feed, Type type)
{
_feed = feed;
_type = type;
}
#endregion
#region Methodes
public override void ExecuteResult(ControllerContext context)
{
// Get the response
HttpResponseBase response = context.HttpContext.Response;
// Add header en encoding
response.ContentEncoding = Encoding.UTF8;
var settings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(false)
};
using (XmlWriter writer = XmlWriter.Create(response.Output, settings))
{
if (_type==Type.Atom)
{
Atom10FeedFormatter atomformatter = new Atom10FeedFormatter(_feed);
atomformatter.WriteTo(writer);
}
else
{
Rss20FeedFormatter rssformatter = new Rss20FeedFormatter(_feed);
rssformatter.WriteTo(writer);
}
}
}
#endregion
}
Je crois que cela se passe de commentaires supplémentaires.
Facile non?