基于.NetCore开发博客项目 StarBlog - (29) 开发RSS订阅功能
前言
最近忙中偷闲把博客的评论功能给做完了,我可以说这个评论功能已经达到「精致」的程度了
但在正式发布之前,先卖个关子,来介绍一下另一个新功能——RSS订阅
RSS是啥
来自hk gov新闻网的介绍~
RSS 是簡易資訊聚合(Really Simple Syndication) 的簡稱,RSS採用一個 XML 的檔案格式,只要你把RSS內容的網址,加到你的RSS閱讀軟件 (RSS Reader),每當該網頁內容更新時,更新了的摘要便會自動加到你的閱讀軟件之內,通知你有關內容。透過 RSS 的使用,供應網頁內容的人可以很容易地產生並傳播新聞鏈結、標題和摘要等資料。
一个网站支持 RSS,就意味着每当它新发布一篇新文章,就会往一个位于特定网址的文件中,以特定的语法(具体而言是 XML 标记语言或 JSON)增加一条记录,列明这篇文章的标题、作者、发表时间和内容(可以是全文,也可以是摘要)等信息。这样,用户只要搜集所有他感兴趣的网站提供的这种文件的网址,并不时检查这些文件内容的更新,就能知道这些网站是否、何时发布了什么内容。RSS 阅读器的核心功能,就是存储用户订阅的 RSS 地址,以固定的频率自动检查更新,并将其内容转换为易读的格式呈现给用户。
为啥要开发RSS功能
起先是有用户在StarBlog项目github里提了个issue
我觉得挺不错的,实现起来也不难,所以就着手安排实现了。
对于现在的网友来说,这算是个比较陌生和小众的东西,RSS 的对立面是算法推荐,像微信公众号、知乎、微博、今日头条等平台。 且不说算法推送平台广告多,迁移麻烦的问题。算法推荐的特点是,你不需要刻意选择,算法会根据你的喜好,给你推送内容。这样一来,你几乎没有选择的余地,在不断被「喂饱」中逐渐失去判断的能力。更可怕的地方在于,它替你定义了你的画像,然后把你潜移默化中变成了它所认为的你。「大数据杀熟」的东窗事发绝非偶然,用算法窥视用户隐私是当今互联网公司的通配。
做信息的主人,而不是奴隶。RSS 是一种公开的协议,可自由更换平台与客户端。重要的一点是,获取信息的权力完全自治。RSS 相比算法推荐,拥有了可控性和安全感,隐私完全掌握在自己手里。
RSS版本 - Atom 与 RSS2.0
我一开始以为 RSS2.0 比 Atom1.0 更新,结果完全搞反了~
简单来说:ATOM是RSS2.0的改进方案,因为RSS2.0的标准已经冻结,所以才出了ATOM。主要改进是ATOM可以通过标签识别一个内容是否是全文输出而RSS2.0不可以。
同时,ATOM不仅能够判断出内容是否是全文输出,在终端软件使用该FEED时,还可以从中得到那一部分是“摘要”那一部分是“全文”方便进行区别显示。
那肯定选新版的啦,直接用 Atom1.0 版本。
实现
一开始我是打算找个第三方库,可以直接和AspNetCore很好地结合在一起的那种。
不过没有找到,但是我发现 C# 标准库居然有提供对 RSS 的支持~ 那还要啥自行车,立刻安排!
安装依赖
虽然是「标准库」但因为现在 .net core 是很轻的,所以还是需要手动添加个 nuget 包才可以用。
dotnet add package System.ServiceModel.Syndication
这个 Syndication 库可以很方便的创建 RSS 订阅。
下面分步骤实现
添加接口
添加 StarBlog.Web/Controllers/RssController.cs 文件
[ApiController]
[Route("feed")]
[ApiExplorerSettings(IgnoreApi = true)]
public class RssController : ControllerBase {
private readonly IBaseRepository<Post> _postRepo;
public RssController(IBaseRepository<Post> postRepo) {
_postRepo = postRepo;
}
[ResponseCache(Duration = 1200)]
[HttpGet]
public async Task<IActionResult> Index() {
}
}
接着在 Index 方法里面写代码
创建 feed
var feed = new SyndicationFeed("StarBlog", "程序设计实验室,一个技术探索与知识分享的平台", new Uri("http://blog.deali.cn"), "RSSUrl", DateTime.Now) {
Copyright = new TextSyndicationContent($"{DateTime.Now.Year} DealiAxy")
};
传入的参数分别是标题、说明、网站地址、订阅ID和最后更新时间。
这里只是例子,所以把更新时间直接写成当前时间了,实际上应该把最新文章的时间写进去。
添加文章
把博客的文章添加到订阅源里
var items = new List<SyndicationItem>();
var posts = await _postRepo.Where(a => a.IsPublish && a.CreationTime.Year == DateTime.Now.Year)
.Include(a => a.Category)
.ToListAsync();
foreach (var item in posts) {
var postUrl = Url.Action("Post", "Blog", new { id = item.Id }, HttpContext.Request.Scheme);
items.Add(new SyndicationItem(item.Title, item.Summary, new Uri(postUrl), item.Id, item.LastUpdateTime) {
Categories = { new SyndicationCategory(item.Category?.Name) },
Authors = { new SyndicationPerson("admin@deali.cn", "DealiAxy", "https://deali.cn") },
PublishDate = item.CreationTime
});
}
feed.Items = items;
这里我把今年已发布的文章都放进订阅源里。
RSS文章内容通过 SyndicationItem 构造方法的第二个参数传入,为了实例代码简洁,我直接偷懒使用纯文本的 summary
如果要让 RSS 阅读器显示文章的时候图文并茂,应该使用 HTML 格式的文章内容,可以把 item.Summary 换成以下代码
new TextSyndicationContent(PostService.GetContentHtml(item), TextSyndicationContentKind.Html)
生成xml
最后,因为 RSS 是使用 XML 格式的,所以最后需要使这个接口返回 XML 数据。
var settings = new XmlWriterSettings {
Async = true,
Encoding = Encoding.UTF8,
NewLineHandling = NewLineHandling.Entitize,
NewLineOnAttributes = true,
Indent = true
};
using var stream = new MemoryStream();
await using var xmlWriter = XmlWriter.Create(stream, settings);
var rssFormatter = new Atom10FeedFormatter(feed);
rssFormatter.WriteTo(xmlWriter);
await xmlWriter.FlushAsync();
return File(stream.ToArray(), "application/rss+xml; charset=utf-8");
注意 var rssFormatter = new Rss20FeedFormatter(feed, false); 这行代码,表示我们用的 RSS 版本是 Atom1.0。
如果要用 RSS2.0 ,可以换成以下代码,第二个参数设置为 false 代表不把扩展语法渲染成 Atom 1.0 的样式。
var rssFormatter = new Rss20FeedFormatter(feed, false);
完整代码
完整代码见 github ~
https://github.com/Deali-Axy/StarBlog/blob/dev/StarBlog.Web/Controllers/RssController.cs
最终效果
RSS 订阅需要使用客户端阅读
这里我使用了一个开源的Windows客户端 Fluent Reader
将 blog.deali.cn/feed 添加到订阅源之后,就可以看到今年发布的文章了

搞定,收工~
参考资料
- https://mitchelsellers.com/blog/article/creating-an-rss-feed-in-asp-net-core-3-0
- https://www.news.gov.hk/chi/rss/index.html
- https://sspai.com/post/56198
- https://www.zhihu.com/question/19593963/answer/12361526
基于.NetCore开发博客项目 StarBlog - (29) 开发RSS订阅功能的更多相关文章
- 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (22) 开发博客文章相关接口
前言 本文介绍博客文章相关接口的开发,作为接口开发介绍的第一篇,会写得比较详细,以抛砖引玉,后面的其他接口就粗略带过了,着重于WebApi开发的周边设施. 涉及到的接口:文章CRUD.置顶文章.推荐文 ...
- 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (17) 自动下载文章里的外部图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (18) 实现本地Typora文章打包上传
前言 九月太忙,只更新了三篇文章,本来这个功能是从九月初就开始做的,结果一直拖到现在国庆假期才有时间完善并且写文章~ 之前我更新了几篇关于 Python 的文章,有朋友留言问是不是不更新 .Net 了 ...
- 基于.NetCore开发博客项目 StarBlog - (19) Markdown渲染方案探索
前言 笔者认为,一个博客网站,最核心的是阅读体验. 在开发StarBlog的过程中,最耗时的恰恰也是文章的展示部分功能. 最开始还没研究出来如何很好的使用后端渲染,所以只能先用Editor.md组件做 ...
随机推荐
- kubernetes核心实战(九)
14.Ingress 检查是否有安装 [root@k8s-master-node1 ~/yaml/test]# kubectl get pod,svc -n ingress-nginx NAME RE ...
- 生产事故-记一次特殊的OOM排查
入职多年,面对生产环境,尽管都是小心翼翼,慎之又慎,还是难免捅出篓子.轻则满头大汗,面红耳赤.重则系统停摆,损失资金.每一个生产事故的背后,都是宝贵的经验和教训,都是项目成员的血泪史.为了更好地防范和 ...
- 【Voyage】GDOI 2023 旅游记 || ECHO.
\(\color{#FFFFFF}{那是什么样的旅途呢}\) \(\color{#FFFFFF}{真的会害怕很多东西呢.想想害怕的其实不止这样一件事,便产生了"其实都一样没关系的,都应该踏过 ...
- Semantic Kernel 入门系列:🔥Kernel 内核和🧂Skills 技能
理解了LLM的作用之后,如何才能构造出与LLM相结合的应用程序呢? 首先我们需要把LLM AI的能力和原生代码的能力区分开来,在Semantic Kernel(以下简称SK),LLM的能力称为 sem ...
- Disruptor-简单使用
前言 Disruptor是一个高性能的无锁并发框架,其主要应用场景是在高并发.低延迟的系统中,如金融领域的交易系统,游戏服务器等.其优点就是非常快,号称能支撑每秒600万订单.需要注意的是,Disru ...
- node使用node-xlsx实现excel的下载与导入,保证你看的明明白白
需求简介 很多时候,我们都会有这样一个业务. 将列表中的数据导出为excel. 这样做的目的是为了方便查看,同时可以保存在本地归档. 还可以将导出的Excel后的数据进行加工. node-xlsx 的 ...
- 任务拆解,悠然自得,自动版本的ChatGPT,AutoGPT自动人工智能AI任务实践(Python3.10)
当我们使用ChatGPT完成某些工作的时候,往往需要多轮对话,比如让ChatGPT分析.翻译.总结一篇网上的文章或者文档,再将总结的结果以文本的形式存储在本地.过程中免不了要和ChatGPT" ...
- Linux操作系统网络模块
Linux操作系统的网络模块是负责网络通信的核心部分.它通过实现各种协议和算法,使得计算机能够在网络中进行数据交换和通信.网络模块主要包括以下几个方面的功能: (1)IP协议栈:负责处理网络层的数据包 ...
- .NET周报 【4月第3期 2023-04-15】
国内文章 Semantic Kernel 入门系列: Planner 规划器 https://www.cnblogs.com/xbotter/p/semantic_kernel_introductio ...
- 当我第一次通过Kotlin和Compose来实现一个Canvas时, 我收获了什么?
当我第一次通过Kotlin和Compose来实现一个Canvas时, 我收获了什么? 自从2019年Google推荐Kotlin为Android开发的首选语言以来已经经历了将近四年的时间, Compo ...