RSS Feeds em ASP.NET MVC

113

Como você recomendaria lidar com RSS Feeds na ASP.NET MVC? Usando uma biblioteca de terceiros? Usando o material RSS no BCL? Apenas fazendo uma visualização RSS que renderiza o XML? Ou algo completamente diferente?

Lance Fisher
fonte
Usando o RssToolkit, você só precisa ter um único arquivo .ashx em seu projeto para gerar feed RSS. Então você pode reescrever seu URL para um amigável. Acho que não há nada contra MVC nessa abordagem.
Mahdi Taghizadeh
Aqui está um post de acompanhamento que leva a ideia RssActionResult um pouco mais longe com uma classe de resultado SyndicationAction generalizada, bem como um filtro get condicional NotModified 304. 58bits.com/blog/…
Blue Waters
Eu escrevi um RssResult que você pode dar uma olhada se quiser. Ele deve atender aos seus requisitos http://www.wduffy.co.uk/blog/rssresult-aspnet-mvc-rss-actionresult/
WDuffy
1
Apenas para atualizar esta questão a partir de 18 meses após a última edição - parecia razoável questionar 'as coisas mudaram com iterações para .net e mvc que mudariam como abordamos o problema de gerenciamento de feed'? O consenso (por meio de um thread diferente do SO) é que 'Sem alterações fundamentais - esse continua sendo o seu melhor conjunto de alternativas'.
JustSteve,
má sugestão para ASP.NET MVC.
tugberk

Respostas:

64

Aqui está o que eu recomendo:

  1. Crie uma classe chamada RssResult que herda a classe base abstrata ActionResult.
  2. Substitua o método ExecuteResult.
  3. ExecuteResult tem o ControllerContext passado a ele pelo chamador e com isso você pode obter os dados e o tipo de conteúdo.
  4. Depois de alterar o tipo de conteúdo para rss, você desejará serializar os dados em RSS (usando seu próprio código ou outra biblioteca) e escrever na resposta.

  5. Crie uma ação em um controlador que deseja retornar rss e defina o tipo de retorno como RssResult. Pegue os dados do seu modelo com base no que você deseja retornar.

  6. Então, qualquer solicitação para esta ação receberá rss de quaisquer dados que você escolher.

Essa é provavelmente a maneira mais rápida e reutilizável de retornar o rss como uma resposta a uma solicitação na ASP.NET MVC.

Dale Ragan
fonte
10
Hanselman tem uma solução semelhante (vídeo: começando em torno de 41m) onde ele herda de FileResult. Ao fazer isso, você pode fazer com que o construtor de sua classe seja chamado base("application/rss+xml")e evitar as etapas 3 e 4. Ele substitui ExecuteResult, mas não é vital. Ele também atalhos de um monte de código normalmente-caseira e utiliza os 3.5+ características SyndicateItem, SyndicateFeede Rss20FeedFormatter.
patridge
@Dale: é possível escrever na resposta quando você deseja dar saída para alimentar uma visão parcial? Obrigado.
Christian
1
Link atualizado do vídeo de Hanselman de meu comentário anterior.
patridge 02 de
150

O .NET framework expõe classes que lidam com sindicação: SyndicationFeed etc. Então, em vez de fazer a renderização você mesmo ou usar alguma outra biblioteca RSS sugerida, por que não deixar o framework cuidar disso?

Basicamente, você só precisa do seguinte ActionResult personalizado e está pronto para começar:

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

Agora, em sua ação de controle, você pode simplesmente retornar o seguinte:

return new RssActionResult() { Feed = myFeedInstance };

Há um exemplo completo em meu blog em http://www.developerzen.com/2009/01/11/aspnet-mvc-rss-feed-action-result/

Eran Kampf
fonte
34

Eu concordo com Haacked. Atualmente, estou implementando meu site / blog usando a estrutura MVC e optei pela abordagem simples de criar uma nova visualização para 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>

Para obter mais informações, consulte (plug sem vergonha) http://rickyrosario.com/blog/creating-an-rss-feed-in-asp-net-mvc

Ricky
fonte
4
para uso do Razor: @model PageModel @ {Response.ContentType = "application / rss + xml"; } <? xml version = "1.0" encoding = "UTF-8"?>
Anthony Johnston
2
Qual sobrecarga? você quer dizer o fato de que está escrevendo menos código para realizar a mesma coisa de uma forma mais legível?
Paul,
12

Outra abordagem maluca, mas com sua vantagem, é usar uma visualização normal .aspx para renderizar o RSS. Em seu método de ação, basta definir o tipo de conteúdo apropriado. O único benefício dessa abordagem é que é fácil entender o que está sendo renderizado e como adicionar elementos personalizados, como geolocalização.

Então, novamente, as outras abordagens listadas podem ser melhores, eu apenas não as usei. ;)

Haacked
fonte
3
@Haacked: O mundo está cheio de RSS XML inválido gerado por um sistema de modelos. Por favor, não acrescente confusão! Ricky, codificação HTML! = Codificação XML.
Brad Wilson
Abaixo está a documentação do Html Encode do MSDN:> Devido aos detalhes de implementação atuais, esta função pode ser usada como uma função xmlEncode. Atualmente, todas as entidades nomeadas usadas por esta função também são entidades nomeadas predefinidas xml. Eles são <> "& codificados como & lt; & gt; & quot; e & amp ;. Outras entidades são decimais como & # 160 ;. http://msdn.microsoft.com/en-us/library/73z22y6h.aspx
Ricky
Como você pode garantir que o XML é válido fazendo isso? Seria bom se a renderização da visualização fosse desacoplada de uma solicitação da web de entrada, para tornar as visualizações XML ou modelos de e-mail como Ruby on Rails possíveis.
Paco
Em vez de usar um mecanismo de exibição, você pode criar um RssResult que deriva de ActionResult. Fazemos isso com o JsonResult, que serializa o objeto para JSON. No seu caso, você encontrará algum serializador (acho que o WCF tem um) que serializa para RSS.
Haacked de
8

Eu consegui isso de Eran Kampf e um vídeo de Scott Hanselman (esqueci o link), então é apenas um pouco diferente de alguns outros posts aqui, mas espero que seja útil e copie e cole pronto como um feed de rss de exemplo.

Do meu 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 o código do controlador ....

    [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
fonte