Flux RSS dans ASP.NET MVC

113

Comment recommanderiez-vous de gérer les flux RSS dans ASP.NET MVC? Vous utilisez une bibliothèque tierce? Vous utilisez le contenu RSS dans la BCL? Vous venez de créer une vue RSS qui rend le XML? Ou quelque chose de complètement différent?

Lance Fisher
la source
En utilisant RssToolkit, il vous suffit d'avoir un seul fichier .ashx dans votre projet pour générer un flux RSS. Ensuite, vous pouvez réécrire son URL en une URL conviviale. Je pense qu'il n'y a rien contre MVC dans cette approche.
Mahdi Taghizadeh
Voici un article de suivi qui pousse un peu plus loin l'idée de RssActionResult avec une classe de résultats SyndicationAction généralisée ainsi qu'un filtre d'obtention conditionnel 304 NotModified. 58bits.com/blog/…
Blue Waters
J'ai écrit un RssResult que vous pouvez consulter si vous le souhaitez. Il devrait répondre à vos exigences http://www.wduffy.co.uk/blog/rssresult-aspnet-mvc-rss-actionresult/
WDuffy
1
Juste pour mettre à jour cette question à partir de 18 mois après la dernière modification - Il semblait raisonnable de se demander `` les choses ont-elles changé avec les itérations à la fois vers .net et mvc qui changeraient notre façon d'aborder le problème de la gestion des flux ''? Le consensus (via un autre fil de discussion SO) est que, "Pas de changements fondamentaux - cela reste votre meilleur ensemble d'alternatives."
justSteve
mauvaise suggestion pour ASP.NET MVC.
tugberk

Réponses:

64

Voici ce que je recommande:

  1. Créez une classe appelée RssResult qui hérite de la classe de base abstraite ActionResult.
  2. Remplacez la méthode ExecuteResult.
  3. ExecuteResult a le ControllerContext qui lui est passé par l'appelant et avec cela, vous pouvez obtenir les données et le type de contenu.
  4. Une fois que vous avez changé le type de contenu en rss, vous voudrez sérialiser les données en RSS (en utilisant votre propre code ou une autre bibliothèque) et écrire dans la réponse.

  5. Créez une action sur un contrôleur que vous souhaitez retourner rss et définissez le type de retour sur RssResult. Récupérez les données de votre modèle en fonction de ce que vous souhaitez renvoyer.

  6. Ensuite, toute demande à cette action recevra rss des données que vous choisissez.

C'est probablement le moyen le plus rapide et réutilisable de renvoyer rss a une réponse à une requête dans ASP.NET MVC.

Dale Ragan
la source
10
Hanselman a une solution similaire (vidéo: à partir d'environ 41m) où il hérite de FileResult. Ce faisant, vous pouvez appeler le constructeur de votre classe base("application/rss+xml")et éviter les étapes 3 et 4. Il remplace ExecuteResult, mais ce n'est pas vital. Il raccourcis également beaucoup de code typiquement bure et utilise les caractéristiques 3.5+ SyndicateItem, SyndicateFeedet Rss20FeedFormatter.
patridge
@Dale: est-il possible d'écrire dans la réponse lorsque vous souhaitez générer une sortie pour alimenter une vue partielle? Merci.
Christian
1
Lien mis à jour de la vidéo de Hanselman à partir de mon commentaire précédent.
patridge le
150

Le framework .NET expose les classes qui gèrent la syndation: SyndicationFeed, etc. Donc, au lieu de faire le rendu vous-même ou d'utiliser une autre bibliothèque RSS suggérée, pourquoi ne pas laisser le framework s'en charger?

Fondamentalement, vous avez juste besoin du ActionResult personnalisé suivant et vous êtes prêt à commencer:

public class RssActionResult : ActionResult
{
    public SyndicationFeed Feed { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.ContentType = "application/rss+xml";

        Rss20FeedFormatter rssFormatter = new Rss20FeedFormatter(Feed);
        using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output))
        {
            rssFormatter.WriteTo(writer);
        }
    }
}

Maintenant, dans votre action de contrôleur, vous pouvez simplement retourner ce qui suit:

return new RssActionResult() { Feed = myFeedInstance };

Il y a un échantillon complet sur mon blog à http://www.developerzen.com/2009/01/11/aspnet-mvc-rss-feed-action-result/

Eran Kampf
la source
34

Je suis d'accord avec Haacked. J'implémente actuellement mon site / blog en utilisant le framework MVC et j'ai opté pour une approche simple de création d'une nouvelle vue pour RSS:

<%@ Page ContentType="application/rss+xml" Language="C#" AutoEventWireup="true" CodeBehind="PostRSS.aspx.cs" Inherits="rr.web.Views.Blog.PostRSS" %><?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>ricky rosario's blog</title>
<link>http://<%= Request.Url.Host %></link>
<description>Blog RSS feed for rickyrosario.com</description>
<lastBuildDate><%= ViewData.Model.First().DatePublished.Value.ToUniversalTime().ToString("r") %></lastBuildDate>
<language>en-us</language>
<% foreach (Post p in ViewData.Model) { %>
    <item>
    <title><%= Html.Encode(p.Title) %></title>
    <link>http://<%= Request.Url.Host + Url.Action("ViewPostByName", new RouteValueDictionary(new { name = p.Name })) %></link>
    <guid>http://<%= Request.Url.Host + Url.Action("ViewPostByName", new RouteValueDictionary(new { name = p.Name })) %></guid>
    <pubDate><%= p.DatePublished.Value.ToUniversalTime().ToString("r") %></pubDate>
    <description><%= Html.Encode(p.Content) %></description>
    </item>
<% } %>
</channel>
</rss>

Pour plus d'informations, consultez (plug sans vergogne) http://rickyrosario.com/blog/creating-an-rss-feed-in-asp-net-mvc

Ricky
la source
4
pour Razor, utilisez: @model PageModel @ {Response.ContentType = "application / rss + xml"; } <? xml version = "1.0" encoding = "UTF-8"?>
Anthony Johnston
2
Quels frais généraux? vous voulez dire le fait que vous écrivez moins de code pour accomplir la même chose de manière plus lisible?
Paul
12

Une autre approche folle, mais qui a son avantage, consiste à utiliser une vue .aspx normale pour rendre le RSS. Dans votre méthode d'action, définissez simplement le type de contenu approprié. Le seul avantage de cette approche est qu'il est facile de comprendre ce qui est rendu et comment ajouter des éléments personnalisés tels que la géolocalisation.

Là encore, les autres approches énumérées pourraient être meilleures, je ne les ai tout simplement pas utilisées. ;)

Haacked
la source
3
@Haacked: Le monde est plein de XML RSS non valide généré par un système de modèles. S'il vous plaît, n'ajoutez pas au désordre! Ricky, encodage HTML! = Encodage XML.
Brad Wilson
Vous trouverez ci-dessous la documentation de Html Encode de MSDN:> En raison des détails d'implémentation actuels, cette fonction peut être utilisée comme une fonction xmlEncode. Actuellement, toutes les entités nommées utilisées par cette fonction sont également des entités nommées prédéfinies au format XML. Ils sont <> "& encodés en & lt; & gt; & quot; et & amp ;. Les autres entités sont encodées en décimal comme & # 160 ;. http://msdn.microsoft.com/en-us/library/73z22y6h.aspx
Ricky
Comment pouvez-vous vous assurer que le XML est valide de cette façon? Ce serait bien si le rendu de la vue était découplé d'une requête Web entrante, pour rendre possibles des vues XML ou des modèles d'e-mail comme done ruby ​​on rails.
Paco
Plutôt que d'utiliser un moteur d'affichage, vous pouvez créer un RssResult qui dérive d'ActionResult. Nous faisons cela avec le JsonResult qui sérialise l'objet en JSON. Dans votre cas, vous trouverez un sérialiseur (je pense que WCF en a un) qui sérialise en RSS.
Haacked
8

Je l'ai obtenu d'Eran Kampf et d'une vidéo de Scott Hanselman (j'ai oublié le lien), donc ce n'est que légèrement différent de certains autres messages ici, mais j'espère que cela est utile et que le copier-coller est prêt comme exemple de flux rss.

De mon blog

Eran Kampf

using System;
using System.Collections.Generic;
using System.ServiceModel.Syndication;
using System.Web;
using System.Web.Mvc;
using System.Xml;

namespace MVC3JavaScript_3_2012.Rss
{
    public class RssFeed : FileResult
    {
        private Uri _currentUrl;
        private readonly string _title;
        private readonly string _description;
        private readonly List<SyndicationItem> _items;

        public RssFeed(string contentType, string title, string description, List<SyndicationItem> items)
            : base(contentType)
        {
            _title = title;
            _description = description;
            _items = items;
        }

        protected override void WriteFile(HttpResponseBase response)
        {
            var feed = new SyndicationFeed(title: this._title, description: _description, feedAlternateLink: _currentUrl,
                                           items: this._items);
            var formatter = new Rss20FeedFormatter(feed);
            using (var writer = XmlWriter.Create(response.Output))
            {
                formatter.WriteTo(writer);
            }
        }

        public override void ExecuteResult(ControllerContext context)
        {
            _currentUrl = context.RequestContext.HttpContext.Request.Url;
            base.ExecuteResult(context);
        }
    }
}

Et le code du contrôleur ...

    [HttpGet]
public ActionResult RssFeed()
{
    var items = new List<SyndicationItem>();
    for (int i = 0; i < 20; i++)
    {
        var item = new SyndicationItem()
        {
            Id = Guid.NewGuid().ToString(),
            Title = SyndicationContent.CreatePlaintextContent(String.Format("My Title {0}", Guid.NewGuid())),
            Content = SyndicationContent.CreateHtmlContent("Content The stuff."),
            PublishDate = DateTime.Now
        };
        item.Links.Add(SyndicationLink.CreateAlternateLink(new Uri("http://www.google.com")));//Nothing alternate about it. It is the MAIN link for the item.
        items.Add(item);
    }

    return new RssFeed(title: "Greatness",
                       items: items,
                       contentType: "application/rss+xml",
                       description: String.Format("Sooper Dooper {0}", Guid.NewGuid()));

}
TheDev6
la source