❤️ 感谢不看好我们的人 | .NET 框架 Furion v4.9.2.25
感谢看好我们的人,更感谢不看好我们的人
自2023年11月26日以来,Furion 在商业化探索的道路上已走过了五个多月的历程。这段时间里,我们积极组建了一支充满活力和创新精神的新团队,不仅全力投入到下一代 Furion 版本的研发中,还同步研发了多款具有市场竞争力的商业应用产品。
起初,我们担心商业化的进程可能会引发市场的抵触和疑虑。然而,事实却证明我们的担忧是多余的。通过不断的努力和优化,我们逐渐吸引了越来越多的精准用户,他们不仅认可我们的价值,还愿意与我们携手共进,共同成长。更令人欣喜的是,这类用户的数量还在持续增长,为我们未来的发展奠定了坚实的基础。
在这个过程中,我们与用户之间建立了深厚的信任和合作关系。用户们可以更加放心地使用 Furion 框架,遇到问题时也能得到我们及时、专业的支持。而我们则通过用户的反馈和需求,不断优化产品功能,提升用户体验,实现了与用户的互利共赢。
此外,我们还通过商业化的收入,进一步壮大了团队规模,吸引了更多优秀的人才加入我们的行列。这使得我们能够更加专注于产品的研发和创新,为用户提供更多、更好的功能和应用产品。
展望未来,我们将继续秉承用户至上的理念,不断优化 Furion 框架和商业应用产品,为用户提供更加便捷、高效、安全的解决方案。同时,我们也期待与更多的合作伙伴携手共进,共同开创更加美好的未来。
最后,
对于那些看好我们的人,我们心怀感激,你们的信任与支持是我们前进的动力。同样我们也珍视那些不看好我们的人,因为你们的质疑与挑战,让我们时刻保持清醒与警觉,不断寻找改进的空间。
在这个阶段,我们其实更期待听到质疑的声音,因为它们能让我们更加深入地审视自己,从而做出更好的决策。逆风翻盘,往往比顺风顺水更具挑战性,也更能体现出我们的价值。
无论外界如何看待我们,我们都坚信,我们正在做的事情是正确的、有意义的,它让我们自己感到快乐,也为更多用户带来了价值。这就是我们前进的动力,也是我们坚持下去的信念。
企业招聘/市场情况
自 Furion 于2023年11月26日启动商业化以来,已成功为 4175 家企业开通文档会员或VIP会员服务,并出具了相应发票。同时,我们在招聘平台上统计到已有 653 个企业发布了招聘岗位,仅2024年4月就有 49 家企业在平台上发布招聘信息。
此外,在 Gitee 平台上,Furion 仓库收获了超过 11K 的 Stars,近 6K 的 Watches,以及 4K 的 Forked。值得一提的是,我们的仓库贡献者已超过 250人,大家的热情参与和贡献是我们不断前行的动力。而在 NuGet 平台,我们的总下载量已接近 1600万,这一数字充分证明了 Furion 的受欢迎程度和广泛应用。
在此,我们衷心感谢大家的支持与信任。未来,我们将继续努力,为大家提供更好的产品和服务。
BOSS 直聘
https://www.zhipin.com/web/geek/job?query=furion&city=100010000
前程无忧
https://we.51job.com/pc/search?jobArea=000000&keyword=furion&searchType=2&keywordType=
项目信息
- Gitee:https://gitee.com/dotnetchina/Furion
- Github:https://github.com/MonkSoul/Furion
- NuGet:https://www.nuget.org/profiles/monk.soul
- 文档:https://furion.net
本期亮点
1. 新增定时任务作业计划工厂 ISchedulerFactory 启停作业 StartJob 和 PauseJob 方法
问题分析
在过去,要启动或暂停某个作业,需遵循一系列步骤:
// 首先要检查作业计划是否存在
-if (_schedulerFactory.TryGetJob(jobId, out var scheduler))
{
// 接着启动作业
- scheduler?.Start();
// 或暂停作业
- scheduler?.Pause();
}
这种操作方式虽然功能完备,但处理大量作业时显得繁琐冗长。
解决方案
现在,我们进行了优化,只需通过以下简洁的调用即可完成操作:
// 轻松启动作业
+_schedulerFactory.TryStartJob(jobId, out var scheduler);
// 便捷暂停作业
+_schedulerFactory.TryPauseJob(jobId, out var scheduler);
此优化显著提升了作业管理的便捷性和效率,操作上更加流畅自如。
2. 新增运行时动态修改 Swagger UI 信息
问题分析
在某些应用场景中,我们可能需要对 Swagger UI 的描述内容进行动态调整,以适应不同需求。为此,可以利用 ISwaggerProvider 接口实现灵活操作。
以下是相关代码示例:
+ public void ChangeSwaggerUI_Information([FromServices] ISwaggerProvider swaggerProvider)
{
// 通过依赖注入的方式,引入 ISwaggerProvider 接口
+ var openApiDocument = swaggerProvider.GetSwagger("Default"); // 获取名为 "Default" 的分组文档
// 直接对文档信息进行修改
+ openApiDocument.Info.Title = "我是新标题";
+ openApiDocument.Info.Description = "我是新描述";
}
以下是相关的屏幕截图:
在这段代码中,我们首先通过依赖注入的方式获取了 ISwaggerProvider 接口的实例,然后调用其 GetSwagger 方法获取了名为 "Default" 的分组文档。接着,我们直接修改了文档中的标题和描述信息,实现了对 Swagger UI 描述内容的动态调整。
3. 新增 AES 加解密支持向量 IV、模式 Mode 和填充 Padding 配置
问题分析
在使用前端库 crypto-js 与后端 Java 进行 AES 加解密操作时,由于先前的 Furion 框架未提供必要的向量 IV(初始化向量)、模式 Mode(加密模式)以及填充 Padding(数据填充方式)的配置选项,这导致了在与其他编程语言进行互操作时,加解密过程出现异常情况。
示例代码
// 要加密的明文
var plainText = "一个应用程序框架,您可以将它集成到任何 .NET/C# 应用程序中。";
// 密钥(必须为 16、24 或 32 字节,这里使用 32 字节)
+ var key = "bda66540c463dfdbe70666019f89e554"; // furion 小写 32 位 MD5 加密字符串
// 自定义偏移量(16 字节),如果不指定,则使用默认值
+ byte[] customIV = { 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f, 0x70, 0x81, 0x92, 0xa3, 0xb4, 0xc5, 0xd6, 0xe7, 0xf8, 0x09 };
// 使用 CBC 模式和 PKCS7 填充进行加密
+ var encryptedText = AESEncryption.Encrypt(plainText, key
+ , customIV // 向量
+ , CipherMode.CBC // 模式
+ , PaddingMode.PKCS7); // 填充
Console.WriteLine("加密后文本: " + encryptedText);
// 使用相同的密钥、偏移量、模式和填充进行解密
+ var decryptedText = AESEncryption.Decrypt(encryptedText, key
+ , customIV // 向量
+ , CipherMode.CBC // 模式
+ , PaddingMode.PKCS7); // 填充
Console.WriteLine("解密后文本: " + decryptedText);
输出结果
+ 加密后文本: Gis8TV5vcIGSo7TF1uf4Ceu2xkJjjXomVxcd7SGBQOi5doe8iu+m1mI+FYK6pTrmhp4vKQEfjNAtbQnZiqjHwWrk0Tt2gPXEcX750PjCvsbA/OQBBc0r/JsJPuW2V5Hf+7fk5b8Q7mqHOwDM8432Ag==
+ 解密后文本: 一个应用程序框架,您可以将它集成到任何 .NET/C# 应用程序中。
4. 修复动态 WebAPI 错误将 CancellationToken 类型当作路由参数
问题分析
在实际应用中,经常需要监控客户端发送的请求是否在中途意外中断,例如服务器尚未完成响应时,用户关闭了浏览器窗口或标签页,或其他不可预见的因素导致请求未能完整执行。
解决方案
针对这种情况,我们可以在 Action 方法的参数列表中增加 CancellationToken 参数。此参数的作用在于能够监听客户端是否提前终止了请求,从而进行相应的处理。
[HttpGet]
+public async Task SomeApi(CancellationToken cancellationToken)
{
// 监听客户端是否终止请求
+ cancellationToken.Register(() =>
+ {
+ Console.WriteLine("用户中断了请求。");
+ });
// 确保在异步方法中使用 cancellationToken
await Task.Run(() => {
// 模拟异步操作
+ }, cancellationToken);
}
注意,在异步方法中,应该确保 CancellationToken 被正确传递并用于可能中断的异步操作。在上面的代码中,我们使用了 Task.Run 来模拟一个异步操作,并将 cancellationToken 作为参数传递,以便在需要时能够中断该操作。
相关文档
对于如何进一步了解和使用 CancellationToken,您可以查阅微软官方文档,了解有关 ASP.NET Core 中最小 API 响应的更多细节:
https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/minimal-apis/responses?view=aspnetcore-8.0
5. 新增粘土对象 Clay 支持无限极组合嵌套
问题分析
在之前的版本中,Clay 粘土对象主要支持通过对象或 JSON 字符串的方式生成,但缺乏对对象属性直接设置粘土对象的支持。
在新版本中,我们实现了对任意组合和嵌套的支持,使得粘土对象更为灵活和强大。
public dynamic TestClay()
{
// 创建粘土对象 package
+ var package = Clay.Object(new
+ {
+ Name = "我是第一层"
+ });
var a3 = Clay.Object(new object[] { });
// 为 a3 数组添加多个对象元素
a3[0] = new
{
Name = "明细1"
};
a3[1] = new
{
Name = "明细2"
};
a3[2] = package; // 将 package 嵌套到 a3中
+ // 创建另一个粘土对象,其中嵌套了 package
+ a3[3] = new
+ {
+ package // 这里直接使用变量名作为键,将 package 作为一个属性嵌套
+ };
+ // 创建粘土对象 policy,其中包含多个嵌套对象
+ var policy = Clay.Object(new
{
search = new
{
hotel_id = 10,
check_in_date = DateTime.Now
},
+ // 在 policy 中嵌套 package 对象
+ package,
+ // 使用匿名类(或类型类)嵌套粘土对象
+ package1 = new
+ {
+ package, // 嵌套 package 对象
+ a3 // 嵌套 a3 数组对象
+ }
});
return policy;
}
最终输出
经过上述代码的构造,我们得到了一个嵌套的粘土对象 policy,其结构如下:
{
"search": {
"hotel_id": 10,
"check_in_date": "2024-04-16T14:37:46.201809+08:00"
},
"package": {
"Name": "我是第一层"
},
"package1": {
"package": {
"Name": "我是第一层"
},
"a3": [
{
"Name": "明细1"
},
{
"Name": "明细2"
},
{
"Name": "我是第一层"
},
{
"package": {
"Name": "我是第一层"
}
}
]
}
}
这个输出的 JSON 结构清晰地展示了 policy 对象内部是如何嵌套 package 和 a3 对象的,以及 a3 数组又是如何包含多个对象元素的。这样的结构使得粘土对象能够灵活处理各种复杂的嵌套场景。
6. 新增动态 WebAPI 支持贴 [Route] 特性动态生成控制器情况
示例代码
在 Furion 框架的演进中,控制器生成的方式发生了显著变化。以往,生成控制器需要满足一系列条件,如派生自 ControllerBase 基类,或添加 [DynamicApiController] 特性,或实现 IDynamicApiController 接口。
现在,我们大大简化了这一过程,只需在类上添加 [Route("路由模板")] 特性,即可轻松生成控制器。
- // [ApiController] // 此特性可选,主要实现模型绑定验证
+[Route("[controller]")] // 仅需添加此路由特性,即可实现控制器的生成
public class RouteController
{
public void Get()
{
}
}
这一改进不仅简化了代码结构,还提高了开发效率,让开发者能够更加专注于业务逻辑的实现。
7. 修复审计日志 Monitor 不支持粘土对象 Clay/dynamic 类似格式化输出
问题分析
粘土对象 赋予了强类型 C# 语言操作对象的能力,使其类似于弱类型语言 JavaScript 的灵活性。
在某些情况下,我们需要在接口中直接返回粘土对象 Clay/dynamic 类型。当引入审计日志 [LoggingMonitor] 支持时,我们发现无法正确输出 JSON 格式。例如:
+[LoggingMonitor]
+public dynamic TestClayMonitor()
{
var clay = Clay.Parse("""
{
"name": "Furion",
"age": 4,
"products": [{
"name": "Furion",
"author": "百小僧"
},
{
"name": "Layx",
"author": "百小僧"
}],
}
""");
+ return clay;
}
输出结果却是:
观察打印结果,我们发现粘土对象被错误地转换成了 key:value 格式,这显然不是期望的结果。
解决方案
在最近的更新中,我们已经修复了这个问题,现在输出格式正确无误:
8. 新增远程情况代理模式支持 [BaseAddress] 特性快速设置客户端 BaseAddress
问题分析
在实际开发中,我们经常会遇到需要对接第三方 API 接口的情况。过去,通常的做法是在全局配置文件如 Program.cs 或 Startup.cs 中统一设置每个接口的 BaseAddress。例如:
services.AddRemoteRequest(options =>
{
+ options.AddHttpClient("weixin", client =>
+ {
+ client.BaseAddress = new Uri("https://weixin.qq.com/");
+ });
});
这种方式虽然可以实现功能,但每次添加新的第三方接口时都需要在全局配置中增加相应的设置,显得不够灵活且不够直观。
解决方案
为了解决上述问题,我们在新版本中引入了 [BaseAddress] 特性。这一特性允许我们在接口级别甚至接口方法级别直接设置 BaseAddress,从而无需在全局配置中进行繁琐的设置。以下是使用新特性的示例:
+[BaseAddress("https://weixin.qq.com/")] // 为整个接口方法设置基础地址
public interface IHttp : IBase
{
[Get("api/theapi")]
Task<HttpResponseMessage> TheApi();
+ [Get("api/otherapi"), BaseAddress("https://v2.weixin.qq.com/")] // 为特定方法设置不同的基础地址
Task<HttpResponseMessage> OtherApi();
}
使用 [BaseAddress] 特性的好处在于,它提供了更加灵活和精细化的配置方式,让我们能够根据不同的接口或方法需求设置不同的 BaseAddress。同时,这也减少了在全局配置中维护大量设置的工作量和出错的可能性。
因此,我们无需再编写如下全局配置代码:
// 不再需要全局配置设置 BaseAddress
// options.AddHttpClient("weixin", client =>
// {
// client.BaseAddress = new Uri("https://weixin.qq.com/");
// });
通过这种方式,我们可以更加高效、简洁地进行接口的配置,提高开发效率和代码的可维护性。
本期更新
-
新特性
- [新增] 远程请求代理模式支持
[BaseAddress]特性快速设置HttpClient客户端BaseAddress4.9.2.25 ⏱️2024.04.19 ea88c95 - [新增] 粘土对象进行固化类型时支持
JsonSerializerOptions序列化配置 4.9.2.24 ⏱️2024.04.17 cc6dd13 - [新增] 动态
WebAPI支持贴[Route]特性动态生成控制器 4.9.2.19 ⏱️2024.04.16 #I9H1QH - [新增] 粘土对象支持无限极组合嵌套功能 4.9.2.19 ⏱️2024.04.16 b02916e
- [新增]
AES加解密支持向量IV、模式Mode和填充Padding配置 4.9.2.18 ⏱️2024.04.15 d549bba - [新增] 定时任务作业计划工厂
ISchedulerFactory启停作业StartJob和PauseJob方法 4.9.2.16 ⏱️2024.04.11 89061ef
- [新增] 远程请求代理模式支持
-
突破性变化
-
问题修复
- [修复] 定时任务创建作业处理程序存在内存溢出风险 4.9.2.25 ⏱️2024.04.19 #I9D0RH
- [修复] 动态
WebAPI不支持[BindNever]特性忽略路由和Action参数设置 4.9.2.25 ⏱️2024.04.19 21599e6 - [修复] 审计日志
Monitor不支持粘土对象Clay/dynamic类型格式化输出 4.9.2.24 ⏱️2024.04.17 d578cfb - [修复] 粘土对象无限嵌套粘土对象且
XElement属性包含type="null"节点出现异常问题 4.9.2.21 ⏱️2024.04.16 9d5870f - [修复] 粘土对象嵌套粘土对象只输出第一个属性问题 4.9.2.20 ⏱️2024.04.16 1a75778
- [修复] 动态
WebAPI错误将CancellationToken类型当作路由参数 4.9.2.19 ⏱️2024.04.16 #I9H14X - [修复] 定时任务因新增
GroupSet功能影响到了原有的SetGroupName逻辑 4.9.2.15 ⏱️2024.04.11 #I9FOU0 9e08278
-
文档
- [更新] 事件总线文档、定时任务文档、规范化接口文档、远程请求文档、粘土对象文档、
FS静态类文档、序列化文档、模块化文档、规范化文档、数据加解密文档、动态WebAPI文档
- [更新] 事件总线文档、定时任务文档、规范化接口文档、远程请求文档、粘土对象文档、












