ASP.NET 使用 SyndicationFeed 输出 Rss
以前生成 RSS 都是使用拼接 Xml 的方式生成的,不仅麻烦而且还不规范。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | #region 输出指定分类编号的消息源内容... /// <summary> /// 输出指定分类编号的消息源内容。 /// </summary> public void OutputFeed() { //int categoryId, string customUrl int categoryId = 0; string customUrl = string .Empty; if (! string .IsNullOrEmpty(RequestUtility.GetQueryString( "CategoryId" ))) { categoryId = Convert.ToInt32(RequestUtility.GetQueryString( "CategoryId" )); } if (! string .IsNullOrEmpty(RequestUtility.GetQueryString( "Custom" ))) { customUrl = RequestUtility.GetQueryString( "Custom" ); } StringBuilder xml = new StringBuilder(); xml.Append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" ); xml.Append( "<rss version=\"2.0\">\n" ); xml.Append( "<channel>\n" ); CategoryInfo category = new CategoryInfo(); if (categoryId == 0 && string .IsNullOrEmpty(customUrl)) { xml.AppendFormat( "<title>{0}</title>\n" , string .Format(MemoryCacheProvider.GetLanguage( "WebRssTitle" , WeilogContext.Current.Application.Prefix), SettingInfo.Name)); } else if (categoryId == 0 && ! string .IsNullOrEmpty(customUrl)) { category = CategoryService.GetCategory(Provider, customUrl); xml.AppendFormat( "<title>{0}</title>\n" , string .Format(MemoryCacheProvider.GetLanguage( "WebCategoryRssTitle" , WeilogContext.Current.Application.Prefix), category.Name, SettingInfo.Name)); } else { category = CategoryService.GetCategory(Provider, categoryId); xml.AppendFormat( "<title>{0}</title>\n" , string .Format(MemoryCacheProvider.GetLanguage( "WebCategoryRssTitle" , WeilogContext.Current.Application.Prefix), category.Name, SettingInfo.Name)); } xml.AppendFormat( "<link>{0}</link>\n" , SettingInfo.Url); xml.AppendFormat( "<description>{0}</description>\n" , SettingInfo.Description); xml.AppendFormat( "<language>{0}</language>\n" , SettingInfo.Language); // <language>zh-cn</language> xml.AppendFormat( "<copyright>{0}</copyright>\n" , "Copyright " + SettingInfo.Name); xml.AppendFormat( "<webMaster>{0}</webMaster>\n" , SettingInfo.SmtpMail); xml.AppendFormat( "<generator>{0}</generator>\n" , WeilogContext.Current.Application.FullVersion); xml.Append( "<image>\n" ); xml.AppendFormat( "\t<title>{0}</title>\n" , SettingInfo.Name); xml.AppendFormat( "\t<url>{0}</url>\n" , "/Common/Images/Logo.jpg" ); xml.AppendFormat( "\t<link>{0}</link>\n" , SettingInfo.Url); xml.AppendFormat( "\t<description>{0}</description>\n" , SettingInfo.Description); xml.Append( "</image>\n" ); int totalRecords = 0; List<PostInfo> articleList = new List<PostInfo>(); articleList = PostService.GetPostList( base .Provider, categoryId, null , null , PostType.Post, null , null , null , OrderField.ByPublishTime, OrderType.Desc, 1, 20, out totalRecords); foreach (PostInfo item in articleList) { xml.Append( "<item>\n" ); xml.AppendFormat( "\t<link>{0}</link>\n" , string .Format(SitePath.PostLinkFormat, SettingInfo.Url, item.Locator)); xml.AppendFormat( "\t<title>{0}</title>\n" , item.Title); xml.AppendFormat( "\t<author>{0}</author>\n" , item.AuthorName); xml.AppendFormat( "\t<category>{0}</category>\n" , CategoryService.GetCategory(Provider, item.CategoryId).Name); xml.AppendFormat( "\t<pubDate>{0}</pubDate>\n" , item.PublishTime); //xml.AppendFormat("\t<guid>{0}</guid>\n", string.Format(WebPath.PostLinkFormat, SettingInfo.Url, item.CustomUrl)); xml.AppendFormat( "\t<description>{0}</description>\n" , StringUtil.CDATA( string .IsNullOrEmpty(item.Password) ? (SettingInfo.RssType == 0 ? item.Excerpt : item.Content) : MemoryCacheProvider.GetLanguage( "MsgEncContent" , WeilogContext.Current.Application.Prefix))); xml.Append( "</item>\n" ); } xml.Append( "</channel>\n" ); xml.Append( "</rss>" ); HttpContext.Current.Response.ContentType = "text/xml" ; HttpContext.Current.Response.Write(xml); } #endregion |
前段时间看老外的项目里用到了 SyndicationFeed 这个类来生成 Rss,索性自己做项目的时候也用了一下,果然事半功倍,只需要简洁的代码便可输出 Rss。我的项目是 MVC 的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /// <summary> /// 文章订阅。 /// </summary> /// <returns>视图的执行结果。</returns> public ActionResult PostFeed() { var feed = new SyndicationFeed( base .Settings[ "Name" ].ToString(), base .Settings[ "Description" ].ToString(), new Uri(Settings[ "Url" ].ToString()), "BlogRSS" , DateTime.UtcNow); if (!( bool )Settings[ "Status" ]) return new FeedActionResult() { Feed = feed }; var items = new List<SyndicationItem>(); var posts = PostService.GetPostList(Provider, Data.Common.OrderField.ByPublishTime, Data.Common.OrderType.Desc, 20); foreach ( var post in posts) { string blogPostUrl = Url.RouteUrl( "Post" , new { Id = post.Id }, "http" ); items.Add( new SyndicationItem(post.Title, post.Content, new Uri(blogPostUrl), String.Format( "Blog:{0}" , post.Id), post.PublishTime)); } feed.Items = items; return new FeedResult() { Feed = feed }; } |
FeedResult 是一个自定义的 ActionResult 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /// <summary> /// 封装一个 RSS 源操作方法的结果并用于代表该操作方法执行框架级操作。 /// </summary> public class FeedResult : ActionResult { /// <summary> /// 声明 RSS 源对象。 /// </summary> public SyndicationFeed Feed { get ; set ; } /// <summary> /// 初始化 <see cref="FeedResult"/> 类的新实例。 /// </summary> public FeedResult() { } /// <summary> /// 通过从 System.Web.Mvc.ActionResult 类继承的自定义类型,启用对操作方法结果的处理。 /// </summary> /// <param name="context">用于执行结果的上下文。 上下文信息包括控制器、HTTP 内容、请求上下文和路由数据。</param> public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.ContentType = "application/rss+xml" ; var rssFormatter = new Rss20FeedFormatter(Feed); using ( var writer = XmlWriter.Create(context.HttpContext.Response.Output)) { rssFormatter.WriteTo(writer); } } } |
最后上一张效果图:
分类:
DotNet
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架