Źródła danych RSS w ASP.NET MVC

113

Jak zalecałbyś obsługę źródeł danych RSS w ASP.NET MVC? Korzystasz z biblioteki innej firmy? Korzystasz z RSS w BCL? Po prostu tworzysz widok RSS, który renderuje XML? A może coś zupełnie innego?

Lance Fisher
źródło
Używając RssToolkit, potrzebujesz tylko jednego pliku .ashx w swoim projekcie, aby wygenerować kanał RSS. Następnie możesz przepisać jego adres URL na przyjazny. Myślę, że w tym podejściu nie ma nic przeciwko MVC.
Mahdi Taghizadeh
Oto kolejny post, który przenosi pomysł RssActionResult nieco dalej z uogólnioną klasą wyników SyndicationAction, a także z 304 warunkowym filtrem pobierania NotModified. 58bits.com/blog/…
Blue Waters
Napisałem RssResult, do którego możesz rzucić okiem, jeśli chcesz. Powinien spełniać Twoje wymagania http://www.wduffy.co.uk/blog/rssresult-aspnet-mvc-rss-actionresult/
WDuffy
1
Wystarczy zaktualizować to pytanie od 18 miesięcy po ostatniej edycji - wydaje się rozsądne pytanie „czy coś zmieniło się wraz z iteracjami zarówno w .net, jak i mvc, co zmieniłoby nasze podejście do problemu zarządzania paszą”? Konsensus (poprzez inny wątek SO) jest taki, że „bez fundamentalnych zmian - to pozostaje najlepszy zestaw alternatyw”.
justSteve
zła sugestia dotycząca ASP.NET MVC.
tugberk

Odpowiedzi:

64

Oto co polecam:

  1. Utwórz klasę o nazwie RssResult, która dziedziczy po abstrakcyjnej klasie bazowej ActionResult.
  2. Zastąp metodę ExecuteResult.
  3. ExecuteResult ma ControllerContext przekazany do niego przez obiekt wywołujący, dzięki czemu można uzyskać dane i typ zawartości.
  4. Gdy zmienisz typ zawartości na rss, będziesz chciał serializować dane do RSS (używając własnego kodu lub innej biblioteki) i napisać do odpowiedzi.

  5. Utwórz akcję na kontrolerze, który chcesz zwrócić rss i ustaw typ zwracania jako RssResult. Pobierz dane z modelu na podstawie tego, co chcesz zwrócić.

  6. Wtedy każde żądanie dotyczące tej akcji otrzyma rss dowolnych danych, które wybierzesz.

Jest to prawdopodobnie najszybszy i możliwy do ponownego użycia sposób zwrócenia odpowiedzi na żądanie w ASP.NET MVC.

Dale Ragan
źródło
10
Hanselman ma podobne rozwiązanie (wideo: od ok. 41 m), gdzie dziedziczy po FileResult. Robiąc to, możesz wywołać konstruktor swojej klasy base("application/rss+xml")i uniknąć kroków 3 i 4. Zastępuje on ExecuteResult, ale nie jest to istotne. On również skróty dużo kodu typowo samodziałowego i wykorzystuje 3.5+ cechy SyndicateItem, SyndicateFeedoraz Rss20FeedFormatter.
patridge
@Dale: czy można napisać do odpowiedzi, gdy chcesz wyprowadzić kanał do częściowego widoku? Dzięki.
Christian
1
Zaktualizowany link do wideo Hanselmana z mojego poprzedniego komentarza.
patridge
150

Platforma .NET udostępnia klasy, które obsługują syndykację: SyndicationFeed itp. Więc zamiast wykonywać renderowanie samodzielnie lub korzystać z innej sugerowanej biblioteki RSS, dlaczego nie pozwolić, aby framework się tym zajął?

Zasadniczo potrzebujesz tylko następującego niestandardowego ActionResult i jesteś gotowy do pracy:

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

Teraz w akcji kontrolera możesz po prostu zwrócić:

return new RssActionResult() { Feed = myFeedInstance };

Pełna próbka znajduje się na moim blogu pod adresem http://www.developerzen.com/2009/01/11/aspnet-mvc-rss-feed-action-result/

Eran Kampf
źródło
34

Zgadzam się z Haackedem. Obecnie wdrażam moją witrynę / blog przy użyciu frameworka MVC i zdecydowałem się na proste podejście do tworzenia nowego widoku dla 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>

Aby uzyskać więcej informacji, sprawdź (bezwstydna wtyczka) http://rickyrosario.com/blog/creating-an-rss-feed-in-asp-net-mvc

Ricky
źródło
4
do użytku Razor: @model PageModel @ {Response.ContentType = "application / rss + xml"; } <? xml version = "1.0" encoding = "UTF-8"?>
Anthony Johnston,
2
Jakie koszty ogólne? masz na myśli fakt, że piszesz mniej kodu, aby osiągnąć to samo w bardziej czytelny sposób?
Paul
12

Kolejnym szalonym podejściem, ale ma swoją zaletę, jest użycie normalnego widoku .aspx do renderowania RSS. W swojej metodzie akcji wystarczy ustawić odpowiedni typ zawartości. Jedną z zalet tego podejścia jest to, że łatwo jest zrozumieć, co jest renderowane i jak dodawać niestandardowe elementy, takie jak geolokalizacja.

Z drugiej strony, inne wymienione podejścia mogą być lepsze, po prostu ich nie używałem. ;)

Haacked
źródło
3
@Haacked: Świat jest pełen nieprawidłowego XML RSS wygenerowanego przez system szablonów. Proszę, nie dodawaj do bałaganu! Ricky, kodowanie HTML! = Kodowanie XML.
Brad Wilson,
Poniżej znajduje się dokumentacja Html Encode z MSDN:> Ze względu na szczegóły bieżącej implementacji, ta funkcja może być używana jako funkcja xmlEncode. Obecnie wszystkie nazwane jednostki używane przez tę funkcję są również wstępnie zdefiniowanymi nazwanymi jednostkami XML. Są one <> „& zakodowane jako & lt; & gt; & quot; i & amp ;. Inne jednostki są zakodowane dziesiętnie, np. & # 160 ;. http://msdn.microsoft.com/en-us/library/73z22y6h.aspx
Ricky,
Jak możesz upewnić się, że XML jest prawidłowy, robiąc w ten sposób? Byłoby miło, gdyby renderowanie widoku zostało oddzielone od przychodzącego żądania internetowego, aby umożliwić widoki XML lub szablony wiadomości e-mail, takie jak gotowe ruby ​​on rails.
Paco
Zamiast używać silnika widoku, można utworzyć RssResult, który pochodzi z ActionResult. Robimy to za pomocą JsonResult, który serializuje obiekt do formatu JSON. W twoim przypadku znajdziesz serializator (myślę, że WCF ma taki), który serializuje do RSS.
Haacked
8

Dostałem to od Erana Kampfa i wideo Scotta Hanselmana (zapomniałem linku), więc różni się tylko nieznacznie od niektórych innych postów tutaj, ale mam nadzieję, że jest pomocny i skopiuj wklej gotowy jako przykładowy kanał rss.

Z mojego bloga

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

A kod kontrolera ...

    [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
źródło