ASP.NET MVC中的RSS订阅源

115

你会如何建议在ASP.NET MVC中处理RSS Feeds?使用第三方库?使用BCL中的RSS功能?创建一个呈现XML的RSS视图?还是完全不同的方式?


使用RssToolkit,您只需要在项目中拥有一个单独的.ashx文件来生成RSS源。然后,您可以将其URL重写为友好的URL。我认为这种方法对MVC没有任何不利影响。 - Mahdi Taghizadeh
这是一篇后续文章,进一步介绍了RssActionResult的想法,并引入了一个通用的SyndicationAction结果类以及一个304 NotModified条件获取过滤器。http://www.58bits.com/blog/ASPNET-MVC-304-Not-Modified-Filter-For-Syndication-Content.aspx - Blue Waters
如果您愿意,我已经编写了一个RssResult,您可以查看一下。它应该符合您的要求。 http://www.wduffy.co.uk/blog/rssresult-aspnet-mvc-rss-actionresult/ - William
1
仅仅是为了更新这个问题,在距离上次编辑18个月的现在——质疑“随着.NET和MVC的迭代,我们如何处理反馈管理的问题有没有发生改变”似乎是合理的。通过不同的SO线程,共识是,“没有根本性的改变——这仍然是你最好的选择”。 - justSteve
ASP.NET MVC 的建议不好。 - tugberk
我最近写了一篇关于如何在asp.net mvc中创建RSS订阅的文章(http://tech.pro/tutorial/1117/generating-rss-feed-actions-in-aspnet-mvc),这也应该是你所寻找的。 - Leland Richardson
5个回答

150

.NET框架提供了处理 RSS 订阅的类:SyndicationFeed等。因此,不必自己进行渲染或使用其他建议的RSS库,为什么不让框架来处理呢?

基本上,您只需要以下自定义 ActionResult 即可开始:

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

现在在您的控制器操作中,您可以简单地返回以下内容:

return new RssActionResult() { Feed = myFeedInstance };

我的博客上有一个完整的示例,网址为http://www.developerzen.com/2009/01/11/aspnet-mvc-rss-feed-action-result/


65
以下是我的建议:
  1. 创建一个名为RssResult的类,继承自抽象基类ActionResult。
  2. 覆盖ExecuteResult方法。
  3. ExecuteResult方法由调用者传递ControllerContext参数,通过它可以获取数据和内容类型。
  4. 一旦将内容类型更改为RSS,您将需要将数据序列化为RSS(使用您自己的代码或其他库),然后写入响应中。

  5. 在控制器上创建一个操作,您希望将其返回为rss,并将返回类型设置为RssResult。根据要返回的内容从模型中获取数据。

  6. 然后,任何请求该操作的请求都将收到您选择的任何数据的rss。

这可能是以最快且可重复使用的方式作为ASP.NET MVC请求的响应来返回rss。


10
Hanselman有一个类似的解决方案(视频:大约从41分钟开始),他从FileResult继承。通过这样做,您可以让您的类的构造函数调用base("application/rss+xml"),避免步骤3和4。他确实覆盖了ExecuteResult,但这并不是必要的。他还简化了很多通常自己编写的代码,并使用了3.5+的功能,如SyndicateItemSyndicateFeedRss20FeedFormatter - patridge
@Dale:当您想要将输出提供给部分视图时,是否可以写入响应?谢谢。 - Christian
1
在我之前的评论中,汉塞尔曼的视频链接已更新,点击此处进行观看:http://channel9.msdn.com/Events/MIX/MIX10/FT07。 - patridge

34

我同意Haacked的看法。目前我正在使用MVC框架实现我的网站/博客,我选择了简单的方法来创建一个新的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>

欲了解更多信息,请查看(自荐)http://rickyrosario.com/blog/creating-an-rss-feed-in-asp-net-mvc


4
对于 Razor 使用:@model PageModel @{Response.ContentType = "application/rss+xml"; }<?xml version="1.0" encoding="UTF-8" ?> - Anthony Johnston
2
什么开销?你是指以更可读的方式编写更少的代码来完成相同的事情这一事实吗? - Paul

13
另一种疯狂的方法是使用正常的.aspx视图来呈现RSS,但它也有优势。在您的操作方法中,只需设置适当的内容类型即可。这种方法的一个好处是很容易理解正在呈现什么以及如何添加自定义元素,例如地理位置。然而,上述列出的其他方法可能更好,我只是没有使用过它们。 ;)

3
@Haacked:世界上充满了由模板系统生成的无效RSS XML。请不要加入这个混乱中!Ricky,HTML编码不等同于XML编码。 - Brad Wilson
以下是来自 MSDN 的 Html Encode 文档:由于当前实现细节,此函数可用作 xmlEncode 函数。目前,此函数使用的所有命名实体也是 xml 预定义命名实体。它们是 < > " & 编码为 < > " 和 &。其他实体像   一样进行十进制编码。http://msdn.microsoft.com/en-us/library/73z22y6h.aspx - Ricky
你如何确保XML是有效的呢?如果视图渲染与传入的Web请求分离,将会很好,这样就可以像Ruby on Rails一样制作XML视图或电子邮件模板。 - Paco
与其使用视图引擎,你可以创建一个从ActionResult派生的RssResult。我们使用JsonResult来将对象序列化为JSON。在你的情况下,你需要找到一些序列化器(我认为WCF有一个)来将其序列化为RSS。 - Haacked

9

我从Eran Kampf和Scott Hanselman的视频中得到了这个内容(忘记链接了),所以它与这里的其他帖子略有不同,但希望作为一个示例rss源代码,对你有所帮助并可供复制粘贴。

来自我的博客

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

控制器代码...

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

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接