🦉 谋士以身入局,.NET 框架 Furion v4.9.2 发布
谋士以身入局,破局以力行实践。
谋士以身入局,破局以力行实践。世间之事,如同棋局,纷繁复杂,难以一眼洞穿。唯有亲身涉入其中,方能体悟其微妙变化,洞悉其深藏之规律。
人生亦是如此,奇妙无穷,福祸相依。有时,我们会在逆境中遇到转机,峰回路转;有时,又会在顺境中遭遇波折,跌宕起伏。但正是这些起起伏伏,构成了我们丰富多彩的人生画卷。
2024.03.31 百小僧
时间总是在不经意间从每日充实且忙碌的生活中悄悄溜走。距离上一次发版已经过去了整整十天。
随着 Furion 的声誉日益提升,其用户数量也呈现出迅猛的增长态势。作为 .NET 领域的热门流行框架,Furion 在 Gitee 平台上收获了超过 11K 的星星,NuGet 下载量更是突破了 1500 万大关。同时,我们的文档注册用户数量已经达到了 4.8万+,每日浏览量高达 60万+,独立访客数量也超过了 4 万。更令人振奋的是,已经有超过 4100 家企业选择使用 Furion,这充分证明了其在业界的广泛认可与卓越价值。
开源需躬身入局
只要你的开源项目足够风靡,且你对其倾注的心血如同养育子女般深厚,那么在寻求商业化的道路上,难免会遇到一些毫无底线、唯利是图的企业和个人开发者。正因如此,像Elasticsearch、Kibana、MongoDB和Redis这样的知名开源项目,都不得不选择修改其开源协议,以应对这种局面。传统的OSI定义显然已经无法准确概括现代开源运动的复杂性和多样性,因此,越来越多的项目开始倾向于采用更加灵活和适应性强的SSPL协议。
然而,反观国内的开源圈,不少所谓的导师、布道师,甚至是开源平台的创始人,他们中的大多数人都没有亲自经历过从零到一打造一款成功的开源项目,更谈不上实现商业化的蜕变。但即便如此,他们却热衷于以导师的身份来指导我们如何进行开源工作。这不禁让人想起那句评论“文章写尽太平事,不肯俯首见苍生。”,他们或许擅长纸上谈兵,但对于真正的开源世界和其中的艰辛与挑战,却缺乏深入的了解和体验。
项目信息
- Gitee:https://gitee.com/dotnetchina/Furion
- Github:https://github.com/MonkSoul/Furion
- 文档:https://furion.net
本期亮点
1. 控制器/动态 WebAPI
方法添加 [DisplayName]
特性生成 Swagger
文档注释
问题分析
在默认情况下,当控制器中的 Action
方法需要在 Swagger
中附带注释时,开发者通常会使用 ///
注释语法。例如:
+/// <summary> +/// 我是一段注释 +/// </summary> public void SomeAction() { }
在实际的项目开发中,为了提高代码的可读性和便于后续的审计日志记录,我们更倾向于使用 [DisplayName]
特性来为每一个 Action
方法命名。这会导致代码中存在冗余的注释信息,如下所示:
/// <summary> +/// 新增用户 /// </summary> +[DisplayName("新增用户")] public void SomeAction() { }
解决方案
为了简化这一流程,减少不必要的重复工作,我们提供了一个功能:使 [DisplayName]
特性也能自动生成注释。这样,开发者就无需再额外添加 ///
注释语法,也能在 Swagger
中看到相应的注释信息。
具体实现如下:
-/// <summary> -/// 新增用户 -/// </summary> +[DisplayName("新增用户")] public void SomeAction() { }
通过上述改进,开发者可以更加高效地为 Action
方法添加描述信息,同时保持代码的整洁和可读性。
最终效果
优先级
如果同时提供了 ///
注释和 [DisplayName]
特性,那么后者将覆盖前者。
2. 定时任务持久化 IJobPersistence
接口方法为异步方法
为了避免定时任务持久化存在死锁风险,故将所有方法调整为异步方法(破坏性):
/// <summary> /// 作业调度持久化器 /// </summary> public interface IJobPersistence { /// <summary> /// 作业调度器预加载服务 /// </summary> /// <param name="stoppingToken">取消任务 Token</param> /// <returns><see cref="Task"/></returns> - IEnumerable<SchedulerBuilder> Preload(); + Task<IEnumerable<SchedulerBuilder>> PreloadAsync(CancellationToken stoppingToken); /// <summary> /// 作业计划初始化通知 /// </summary> /// <param name="builder">作业计划构建器</param> /// <param name="stoppingToken">取消任务 Token</param> /// <returns><see cref="Task"/></returns> - SchedulerBuilder OnLoading(SchedulerBuilder builder); + Task<SchedulerBuilder> OnLoadingAsync(SchedulerBuilder builder, CancellationToken stoppingToken); /// <summary> /// 作业信息更改通知 /// </summary> /// <param name="context">作业信息持久化上下文</param> /// <returns><see cref="Task"/></returns> - void OnChanged(PersistenceContext context); + Task OnChangedAsync(PersistenceContext context); /// <summary> /// 作业触发器更改通知 /// </summary> /// <param name="context">作业触发器持久化上下文</param> /// <returns><see cref="Task"/></returns> - void OnTriggerChanged(PersistenceTriggerContext context); + Task OnTriggerChangedAsync(PersistenceTriggerContext context); /// <summary> /// 作业触发记录通知 /// </summary> /// <param name="timeline">作业触发器运行记录</param> /// <returns><see cref="Task"/></returns> - void OnExecutionRecord(TriggerTimeline timeline); + Task OnExecutionRecordAsync(TriggerTimeline timeline); }
最新 IJobPersistence
接口声明:
namespace Furion.Schedule; /// <summary> /// 作业调度持久化器 /// </summary> public interface IJobPersistence { /// <summary> /// 作业调度器预加载服务 /// </summary> /// <param name="stoppingToken">取消任务 Token</param> /// <returns><see cref="Task"/></returns> Task<IEnumerable<SchedulerBuilder>> PreloadAsync(CancellationToken stoppingToken); /// <summary> /// 作业计划初始化通知 /// </summary> /// <param name="builder">作业计划构建器</param> /// <param name="stoppingToken">取消任务 Token</param> /// <returns><see cref="Task"/></returns> Task<SchedulerBuilder> OnLoadingAsync(SchedulerBuilder builder, CancellationToken stoppingToken); /// <summary> /// 作业信息更改通知 /// </summary> /// <param name="context">作业信息持久化上下文</param> /// <returns><see cref="Task"/></returns> Task OnChangedAsync(PersistenceContext context); /// <summary> /// 作业触发器更改通知 /// </summary> /// <param name="context">作业触发器持久化上下文</param> /// <returns><see cref="Task"/></returns> Task OnTriggerChangedAsync(PersistenceTriggerContext context); /// <summary> /// 作业触发记录通知 /// </summary> /// <param name="timeline">作业触发器运行记录</param> /// <returns><see cref="Task"/></returns> Task OnExecutionRecordAsync(TriggerTimeline timeline); }
3. 动态 WebAPI
自定义 [Route]
模板中包含路由约束并且含有大小写字母导致生成错误路由问题
问题分析
在特定情况下,当控制器及其内部的 Action
方法均采用自定义的 [Route]
特性,并且 Action
层面的 [Route]
定义中包含了含有大小写字母的路由参数约束时,系统默认的行为会导致此类参数中的大小写字母被统一转换为小写,从而引发路由匹配失效的问题。比如:
+[Route("api/[controller]/[action]")] public class ShareController : IDynamicApiController { + [Route("/api/share/position/position/{positionID:int}")] public void Position(int positionID) { // ... } }
上述代码片段中,Position
方法的路由约束 {positionID:int}
显然包含一个大小写混合的参数名,其中 ID
部分采用了大写字母。然而,在实际运行时,该参数会被错误地格式化成全小写形式:
/api/share/position/position/{positionid}
这种格式化行为导致原本期望匹配的 positionID
变为了 positionid
,进而使得按照原始定义的大小写格式发送请求时,路由无法正确匹配。
修正效果
针对这一问题,在当前的版本更新中已实施了相应的修复措施,具体做法是:保持路由约束内 {}
包含的参数名称的原始大小写不变。因此,在修复后的场景下,正确的路由格式应该是:
/api/share/position/position/{positionID}
这样一来,路由参数的大小写得以保留,确保了路由匹配逻辑的正确性和一致性。
4. 数据库日志写入接口 IDatabaseLoggingWriter
方法为异步 WriteAsync
问题背景
解决方案
IDatabaseLoggingWriter
接口方法调整(破坏性更改):
- public void Write(LogMessage logMsg, bool flush) + public Task WriteAsync(LogMessage logMsg, bool flush) // 改为异步方法,提升日志写入吞吐量
调整为异步方法之后,可以大大提升数据库日志写入的吞吐量,同时还能实现速率的控制,如:
public async Task WriteAsync(LogMessage logMsg, bool flush) { // 数据库写入~ + await Task.Delay(50); // 延迟 0.05 秒写入数据库,有效减少高频写入数据库导致死锁问题 }
在增强日志提供器的队列容量后,成功缓解了高频日志引发的长时间队列积压和阻塞问题,并显著提升了文件写入的吞吐量。这一改进遵循了“以空间换取时间”的设计理念,即通过适度牺牲部分即时内存来换取更为出色的系统处理效率,从而实现了整体性能的优化。
测试实图
内存情况
文件大小
20万行写入
本期更新
-
新特性
-
突破性变化
-
问题修复
- [修复] 在
.NET8
之后修改System.Text.Json
默认序列化选项引发This JsonSerializerOptions instance is read-only or has already been used in serialization or deserialization.
异常问题 4.9.2.2 ⏱️2024.03.29 9f44653 - [修复] 远程请求
IHttpDispatchProxy
模式配置重试策略无效 4.9.2.1 ⏱️2024.03.29 #I9CK7X - [修复] 动态
WebAPI
自定义[Route]
模板中包含路由约束并且含有大小写字母导致生成错误路由问题 4.9.1.61 ⏱️2024.03.27 cc1a7ec - [修复] 定时任务持久化单个作业触发器订阅执行器出现异常导致持久化服务宕机问题 4.9.1.60 ⏱️2024.03.26 a1014db
- [修复]
EntityFramework Core
反向工程脚本cli.ps1
正则表达式匹配错误 4.9.1.59 ⏱️2024.03.26 !872 @cnbdas
- [修复] 在
-
其他更改
-
文档
- [更新] 事件总线文档、定时任务文档、规范化接口文档、远程请求文档

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
1-2 月规模以上电子信息制造业增加值同比增长 14.6%
工信部已公布2024年1-2月电子信息制造业运行情况。1-2月,我国电子信息制造业生产大幅增长,出口持续改善,效益稳步提升,投资增速加快,区域营收分化明显。 一、生产大幅增长 1-2月,规模以上电子信息制造业增加值同比增长14.6%,增加值增速分别比同期工业、高技术制造业高7.6个和7.1个百分点。 1-2月,主要产品中,手机产量2.34亿台,同比增长26.4%,其中智能手机产量1.72亿台,同比增长31.3%;微型计算机设备产量4381万台,同比下降1.3%;集成电路产量704.2亿块,同比增长16.5%。 二、出口持续改善 1-2月,规模以上电子信息制造业出口交货值同比下降4.8%,比同期工业低5.2个百分点,较2023年提高1.5个百分点。 据海关统计,1-2月,我国出口笔记本电脑1908万台,同比增长7%;出口手机1.24亿台,同比增长12.8%;出口集成电路394亿个,同比增长6.3%。 三、效益稳步提升 1-2月,规模以上电子信息制造业实现营业收入2.14万亿元,同比增长8.2%;营业成本1.89万亿元,同比增长7.1%;实现利润总额418.1亿元,同比增长2.1倍,叠加同...
- 下一篇
云原生 Kafka AutoMQ 1.0.3 正式发布
AutoMQ 是基于云构建的无服务、极速弹性、极具成本效益的下一代 Kafka。100% 兼容 Apache Kafka,无分区数据复制。在无副作用的前提下解决了 Kafka 弹性、运维上的诸多痛点并且带来了数量级的成本降低。 AutoMQ 1.0.3-rc0 版本现已在 Github 仓库正式发布,欢迎大家关注与下载使用。 重要更新 块缓存性能优化:此更新包括对正在处理的数据大小和线程池大小的自适应调整,现在会根据配置的缓存大小和CPU核心自动进行调优。并在此版本中引入了LRU缓存,以加快流集对象查找的速度。这项优化预计将提高追赶读取的整体性能和效率。 网络节流优化:网络节流策略已经过优化,以防止在打开流时发生饥饿。 END 关于我们 AutoMQ 是来自 Apache RocketMQ 和 Linux LVS 项目的核心团队,曾经见证并应对过消息队列基础设施在大型互联网公司和云计算公司的挑战。现在我们基于对象存储优先、存算分离、多云原生等技术理念,重新设计并实现了 Apache Kafka 和 Apache RocketMQ,带来高达 10 倍的成本优势和百倍的弹性效率提升。 ...
相关文章
文章评论
共有0条评论来说两句吧...