Feed RSS in ASP.NET MVC


113

Come consiglieresti di gestire i feed RSS in ASP.NET MVC? Usi una libreria di terze parti? Usi il materiale RSS nel BCL? Stai solo facendo una visualizzazione RSS che renda l'XML? O qualcosa di completamente diverso?


Usando RssToolkit devi solo avere un singolo file .ashx nel tuo progetto per generare feed RSS. Quindi puoi riscrivere il suo URL in uno amichevole. Penso che non ci sia nulla contro MVC in questo approccio.
Mahdi Taghizadeh

Ecco un post di follow-up che porta l'idea di RssActionResult un po 'oltre con una classe di risultati SyndicationAction generalizzata e un filtro get condizionale 304 NotModified. 58bits.com/blog/…
Blue Waters

Ho scritto un RssResult che puoi dare un'occhiata se vuoi. Dovrebbe soddisfare i tuoi requisiti http://www.wduffy.co.uk/blog/rssresult-aspnet-mvc-rss-actionresult/
WDuffy

1
Solo per aggiornare questa domanda a partire da 18 mesi dopo l'ultima modifica - Sembrava ragionevole chiedersi "le cose sono cambiate con le iterazioni sia a .net che a mvc che cambierebbero il modo in cui affrontiamo il problema della gestione dei feed"? Il consenso (tramite un thread SO diverso) è che "Nessun cambiamento fondamentale: questo rimane il miglior set di alternative".
justSteve

cattivo suggerimento per ASP.NET MVC.
tugberk

Risposte:


64

Ecco cosa consiglio:

  1. Crea una classe denominata RssResult che eredita dalla classe base astratta ActionResult.
  2. Eseguire l'override del metodo ExecuteResult.
  3. ExecuteResult ha il ControllerContext passato dal chiamante e con questo è possibile ottenere i dati e il tipo di contenuto.
  4. Una volta modificato il tipo di contenuto in rss, sarà necessario serializzare i dati in RSS (utilizzando il proprio codice o un'altra libreria) e scrivere nella risposta.

  5. Creare un'azione su un controller che si desidera restituire rss e impostare il tipo restituito come RssResult. Prendi i dati dal tuo modello in base a ciò che vuoi restituire.

  6. Quindi qualsiasi richiesta a questa azione riceverà rss di qualsiasi dato tu scelga.

Questo è probabilmente il modo più rapido e riutilizzabile per restituire rss ha una risposta a una richiesta in ASP.NET MVC.


10
Hanselman ha una soluzione simile (video: a partire da circa 41 m) in cui eredita da FileResult. In questo modo, puoi fare in modo che il costruttore della tua classe chiami base("application/rss+xml")ed evitare i passaggi 3 e 4. Esegue l'override di ExecuteResult, ma non è vitale. Ha Tasti di scelta rapida anche un sacco di codice tipicamente casalingo e utilizza le caratteristiche di 3.5+ SyndicateItem, SyndicateFeede Rss20FeedFormatter.
patridge

@Dale: è possibile scrivere nella risposta quando si desidera inviare l'output a una visualizzazione parziale? Grazie.
Christian

1
Link aggiornato del video di Hanselman dal mio commento precedente.
patridge

150

Il framework .NET espone le classi che gestiscono syndation: SyndicationFeed ecc. Quindi, invece di eseguire il rendering da soli o utilizzare qualche altra libreria RSS suggerita, perché non lasciare che il framework se ne occupi?

Fondamentalmente hai solo bisogno del seguente ActionResult personalizzato e sei pronto per partire:

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);
        }
    }
}

Ora nell'azione del controller puoi semplicemente restituire quanto segue:

return new RssActionResult() { Feed = myFeedInstance };

C'è un esempio completo sul mio blog all'indirizzo http://www.developerzen.com/2009/01/11/aspnet-mvc-rss-feed-action-result/


34

Sono d'accordo con Haacked. Attualmente sto implementando il mio sito / blog utilizzando il framework MVC e ho seguito il semplice approccio di creare una nuova vista per 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>

Per ulteriori informazioni, controlla (plug shameless) http://rickyrosario.com/blog/creating-an-rss-feed-in-asp-net-mvc


4
per l'uso di Razor: @model PageModel @ {Response.ContentType = "application / rss + xml"; } <? xml version = "1.0" encoding = "UTF-8"?>
Anthony Johnston

2
Quale sovraccarico? intendi il fatto che stai scrivendo meno codice per ottenere la stessa cosa in un modo più leggibile?
Paul

12

Un altro approccio folle, ma ha il suo vantaggio, consiste nell'usare una normale visualizzazione .aspx per eseguire il rendering dell'RSS. Nel tuo metodo di azione, imposta semplicemente il tipo di contenuto appropriato. L'unico vantaggio di questo approccio è che è facile capire cosa viene visualizzato e come aggiungere elementi personalizzati come la geolocalizzazione.

Inoltre, gli altri approcci elencati potrebbero essere migliori, semplicemente non li ho usati. ;)


3
@Haacked: Il mondo è pieno di RSS XML non validi generati da un sistema di modelli. Per favore non aggiungere al pasticcio! Ricky, HTML encoding! = XML encoding.
Brad Wilson il

Di seguito è riportata la documentazione di Html Encode da MSDN:> A causa dei dettagli di implementazione correnti, questa funzione può essere utilizzata come funzione xmlEncode. Attualmente, tutte le entità denominate utilizzate da questa funzione sono anche entità denominate predefinite xml. Sono <> "& codificati come & lt; & gt; & quot; e & amp;. Altre entità hanno codifica decimale come & # 160 ;. http://msdn.microsoft.com/en-us/library/73z22y6h.aspx
Ricky

Come puoi assicurarti che l'XML sia valido in questo modo? Sarebbe bello se il rendering della vista fosse disaccoppiato da una richiesta web in arrivo, per rendere possibili viste XML o modelli di email come done ruby ​​on rails.
Paco

Anziché utilizzare un motore di visualizzazione, è possibile creare un RssResult che deriva da ActionResult. Lo facciamo con JsonResult che serializza l'oggetto in JSON. Nel tuo caso, troverai un serializzatore (penso che WCF ne abbia uno) che serializza in RSS.
Haacked

8

L'ho ricevuto da Eran Kampf e un video di Scott Hanselman (ho dimenticato il collegamento) quindi è solo leggermente diverso da alcuni altri post qui, ma spero sia utile e copia e incolla pronto come feed RSS di esempio.

Dal mio 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);
        }
    }
}

E il codice del controller ...

    [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()));

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.