v4 版本(归档) - 更新日志
升级前重点关注可能造成【破坏性】的标签类型:、、、
版本号规则:主版本号.次版本号.修订版本号.迭代版本号
- 只要【确认】为框架
bug,则当天修复,当天发版,修订版本号加 1。 - 只要
.NET SDK版本更新,则当天升级,当天发版,修订版本号加 1。 - 如果
.csproj文件有变更,则当天发版,修订版本号加 1。 - 如果新增
扩展包,为了版本号统一,则当天发版,修订版本号加 1。 - 如果涉及到代码重构,则当天发版,次版本号
加 1,修订版本号清 0。 - 如果
.NET SDK主版本号升级,则当天发版,主版本号加 1。
如有意外不能当天发版,则会在 Issue 中说明具体发版时间,正常不会超过 3 天。
v4.9.5(已发布,移除.NET5)
v4.9.5版本细节:https://gitee.com/dotnetchina/Furion/issues/IAIXPQ 2024.08.09 ~ 2024.11.22 🆕
Furion 自 .NET 5 发布之初便应运而生,至今已历经近四年的发展历程。值得注意的是,微软已于 2022 年 5 月 10 日正式终止了对 .NET 5 的支持,然而,Furion 团队 出于对社区责任的坚守,仍额外维持了对 .NET 5 的支持长达两年之久。
早在一年前,Furion 团队便萌生了移除 .NET 5 支持的念头,原因在于 .NET 5 已无法接纳最新的技术革新,且其底层架构要求团队在开发过程中进行大量的兼容性考量,这无形中增加了新功能引入的复杂度与成本。 然而,鉴于仍有相当数量的老用户尚未迁移至 .NET 6 或更高版本,团队毅然决定继续维护,以确保这些用户的平稳过渡,这一维护周期长达两年之久。
如今,.NET 5 在 Furion 框架中的历史使命已圆满完成,这一决定也为即将发布的 Furion v5 版本铺平了道路,使其能够提供更流畅、无缝的升级体验。
因此,我们诚挚地建议目前仍在使用 .NET 5 的朋友们,尽快升级至 .NET 6 或更高版本,以享受最新的技术红利和更好的性能优化。请留意,Furion 框架中最后一个支持 .NET 5 的版本为 Furion v4.9.4.11,之后的新版本将不再兼容 .NET 5。
- 新特性
- 事件总线获取负载数据
context.GetPayload<T>()扩展方法 4.9.5.24 ⏱️2024.11.20 6247d59 - 审计日志
Monitor提供更多异常信息(如业务码,错误码) 4.9.5.19 ⏱️2024.11.09 63372e2 -
EFCore仓储分表删除DeleteFromSegments扩展方法 4.9.5.18 ⏱️2024.10.31 ee14768 -
EFCore仓储分表更新UpdateFromSegments扩展方法 4.9.5.17 ⏱️2024.10.22 2ff66ce - 远程请求代理特性
[BaseAddress]支持读取配置模板 4.9.5.17 ⏱️2024.10.22 ec7f31a -
KSortEncryption生成数据签名(API签名算法) 4.9.5.10 ⏱️2024.09.19 2585d24 - 视图引擎支持完整的
C#代码操作,如数据库操作 4.9.5.10 ⏱️2024.09.19 a571373 -
EFCore进行增删改操作返回受影响行数 4.9.5.9 ⏱️2024.09.18 3315c53 - 动态
WebAPI可配置某个Action不被派生类继承后生成路由的特性[ApiDescriptionSettings(DisableInherite = true)]4.9.5.8 ⏱️2024.09.10 7f248cf - 规范化文档
Swagger支持配置自动在生产环境中启用登录UI配置(LoginInfo.EnableOnProduction) 4.9.5.7 ⏱️2024.09.07 e4020c2 -
EFCore仓储分表插入InsertFromSegments扩展方法 4.9.5.6 ⏱️2024.09.02 ec4c90d -
EFCore数据库逆向工程(DB First)cli.ps1脚本支持生成数据库表名和列名注释 4.9.5.5 ⏱️2024.08.24 efc3404 #I5QJKD #I4IYZ0 #I458RR #I3UNUU -
EFCore数据库逆向工程(DB First)cli.ps1脚本支持在MacOS中使用 4.9.5.3 ⏱️2024.08.14 20099ec -
EFCore仓储分表联合FromSegments扩展方法 4.9.5.2 ⏱️2024.08.12 45432e6 - 支持
EFCore数据库逆向工程(DB First)cli.ps1脚本在终端和主流IDE中使用 4.9.5 ⏱️2024.08.09 a8d3480
- 事件总线获取负载数据
- 突破性变化
- 问题修复
- 自定义授权
Handler发生异常且启用app.UseUnifyResultStatusCodes()中间件时会导致重复写入响应体问题 4.9.5.26 ⏱️2024.11.22 4045aa7 - 程序集扫描无法正确扫描运行时实际模块化依赖列表 4.9.5.23 ⏱️2024.11.17 44fe2bb
- 粘土对象
Clay不支持序列化键大小写配置 4.9.5.22 ⏱️2024.11.15 27a3fbc -
EFCore 9.0出现迁移异常 4.9.5.21 ⏱️2024.11.13 #IB41YD - 启用
Swagger登录UI后输入框不支持特殊字符 4.9.5.16 ⏱️2024.10.16 #IAXDZM - 动态添加程序集插件后无法扫描控制器和动态
WebAPI4.9.5.15 ⏱️2024.10.11 #IAWDBM - 监听配置文件更改出现多次触发问题 4.9.5.13 ⏱️2024.09.29 feb85d2
- 事件总线在
WinForm中将组件作为事件总线处理程序不能更新UI线程问题 4.9.5.12 ⏱️2024.09.23 #IAT1JG -
EFCore分表插入时非数值自增主键类型导致插入异常问题 4.9.5.11 ⏱️2024.09.21 1377e4d - 使用
Nginx部署项目时定时任务看板数据被缓存问题 4.9.5.9 ⏱️2024.09.18 375dfdd -
EFCore数据库逆向工程(DB First)cli.ps1脚本的GUI失效问题 4.9.5.8 ⏱️2024.09.10 36be5cb - 规范化文档
Swagger启用EnableAnnotations(true, true)无效问题 4.9.5.7 ⏱️2024.09.07 9b27cf4 -
EFCore执行更新操作时可能出现DbUpdateConcurrencyException异常问题 4.9.5.7 ⏱️2024.09.07 @Roc.Lee !885 a4db240 - 远程请求解析
Content-Type参数不准确问题 4.9.5.6 ⏱️2024.09.02 281f496 -
Native.GetIdlePort()获取空闲端口存在并发问题 4.9.5.6 ⏱️2024.09.02 d54920c -
EFCore仓储分表联合查询FromSegments方法使用SQLite数据库时表名不带"问题 4.9.5.5 ⏱️2024.08.24 1fdf426 -
Scoped.CreateUowAsync在一些特定情况下会出现空异常情况 4.9.5.5 ⏱️2024.08.24 212badc - 依赖注入模块通过
INamedServiceProvider<>解析服务没有应用拦截器问题 4.9.5.5 ⏱️2024.08.24 0277177 - 日志上下文字典使用
ContainsKey有线程安全问题导致出现重复Key异常 4.9.5.4 ⏱️2024.08.15 53665b5 - 设置日志上下文出现相同
Key导致异常问题 4.9.5.4 ⏱️2024.08.15 8d77141 - 定时任务看板
DateTime类型格式化可能受操作系统时区影响导致异常问题 4.9.5.2 ⏱️2024.08.12 0e13cd6 - 因调整
.NET5脚手架模板导致Swagger无法访问问题 4.9.5.1 ⏱️2024.08.09 #IAJ128 edfc09b - 选项
Options不支持启动时进行模型验证问题 4.9.5 ⏱️2024.08.09 c54d586 - 定时任务看板自定义入口地址必须严格以
/开头且不以/结尾的问题 4.9.5 ⏱️2024.08.09 5798317
- 自定义授权
- 其他更改
- 文档
- 远程请求全局拦截器文档
- 定时任务文档、远程请求文档、脚手架文档、入门文档、
EFCore分表分库文档、EFCore逆向工程文档、动态WebAPI文档、SQL代理文档、视图引擎文档、数据加解密文档、配置选项文档、EFCore分表分库文档、事件总线文档
- 贡献者
- Roc.Lee (@Roc.Lee) !885
- superbisu (@superbisu) !881 !882
v4.9.4(已发布)
v4.9.4版本细节:https://gitee.com/dotnetchina/Furion/issues/IA43PQ 2024.06.11 ~ 2024.08.05 🆕
- 新特性
-
WebApplication.UseDefaultServiceProvider()扩展,可配置框架底层默认使用的IServiceProvider实例 4.9.4.9 ⏱️2024.07.29 d97467c #IAFUNS -
EFCore分页扩展.ToPagedList支持自定义计算TotalCount委托 4.9.4.8 ⏱️2024.07.28 b21ceb1 -
JSON.IsValid(str, [standard])验证字符串是否是标准JSON字符串 4.9.4.8 ⏱️2024.07.28 72b48b4 - 定时任务看板可自动识别是否使用
UTC时间 4.9.4.7 ⏱️2024.07.21 9e3e3bb - 审计日志
Monitor支持通过LoggingMonitorContext静态类设置附加信息 4.9.4.6 ⏱️2024.07.16 a44f096 - 审计日志
Monitor支持打印请求的HTTP协议及版本 4.9.4.6 ⏱️2024.07.16 4a0bc2a -
EFCore查询.WhereCase扩展方法 4.9.4.4 ⏱️2024.07.10 61ff90a - 定时任务可配置是否打印
HTTP作业的结果PrintResponseContent配置 4.9.4.4 ⏱️2024.07.10 93cb339 - 改进定时任务看板,可直观辨别
HTTP作业和其他作业 4.9.4.3 ⏱️2024.07.01 19e8a79 - 改进定时任务看板执行日志,支持查看执行异常信息 4.9.4.3 ⏱️2024.07.01 800a6e4
-
HttpContext获取客户端IPv4地址的GetRemoteIpAddressToIPv4方法xff参数 4.9.4.3 ⏱️2024.07.01 c280dfd - 远程请求上传文件时可以配置是否对文件名进行转义参数
escape4.9.4.1 ⏱️2024.06.17 60836ff -
[UnitOfWork]工作单元特性输出详细的事务日志 4.9.4.1 ⏱️2024.06.17 ef4cb3a #IA457S
-
- 突破性变化
- 定时任务持久化
IJobPersistence.OnExecutionRecordAsync方法签名和ISchedulerFactory.OnExecutionRecord事件参数 4.9.4.2 ⏱️2024.06.21 9d6def5
- 定时任务持久化
查看变化
IJobPersistence接口
- // 旧版本
- Task OnExecutionRecordAsync(TriggerTimeline timeline);
+ // 新版本
+ Task OnExecutionRecordAsync(PersistenceExecutionRecordContext context);
ISchedulerFactory接口
- // 旧版本
- schedulerFactory.OnExecutionRecord += (sender, args) =>
- {
- var timeline = args.Timeline;
- }
+ // 新版本
+ schedulerFactory.OnExecutionRecord += (sender, args) =>
+ {
+ var timeline = args.Context.Timeline; // 通过 .Context 获取更多信息
+ }
- 问题修复
- 远程请求不支持设置携带
charset的Content-Type字符串 4.9.4.10 ⏱️2024.07.30 09ba7fb -
Razor Pages项目[UnitOfWork]工作单元日志打印不同步问题 4.9.4.8 ⏱️2024.07.28 ff42327 -
DateTime/DateTimeOffset使用UTC时间不能正确JSON序列化为本地时间问题 4.9.4.6 ⏱️2024.07.16 b72bf7e - 审计日志
Monitor打印请求地址丢失端口号问题 4.9.4.5 ⏱️2024.07.11 6df5dbd -
HttpRequest.GetRequestUrlAddress扩展获取请求地址丢失端口号问题 4.9.4.5 ⏱️2024.07.11 6df5dbd - 视图引擎
ViewEngine存在内存未释放(内存溢出风险)情况 4.9.4.4 ⏱️2024.07.10 c9e203a - 最新版的
EFCore 9.0.0-preview.5不支持SQL Server 2008/2005/2000数据库 4.9.4.2 ⏱️2024.06.21 6fef13e - 因 889e35a 功能引起的
EFCore排序新异常问题 4.9.4 ⏱️2024.06.11 9271528
- 远程请求不支持设置携带
- 其他更改
- 文档
- 远程请求文档、任务队列文档、定时任务文档、
EFCore查询文档、日志文档、单文件部署文档
- 远程请求文档、任务队列文档、定时任务文档、
v4.9.3(已发布)
v4.9.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I9O5BR 2024.05.10 ~ 2024.06.11 🆕
- 新特性
- 扩展
EFCore排序功能,支持带条件进行排序 4.9.3.20 ⏱️2024.06.11 889e35a - 远程请求发送
application/x-www-form-urlencoded请求时支持字符串Body类型 4.9.3.16 ⏱️2024.06.04 f5c2a20 - 授权失败可以设置
Http状态码context.Fail(statusCode)4.9.3.14 ⏱️2024.05.14 542eb8c - 多语言支持自定义
Url/Cookie/Header参数 4.9.3.14 ⏱️2024.05.30 4f953e7 - 定时任务
Http作业支持配置Timeout超时时间 4.9.3.13 ⏱️2024.05.28 9514fa4 - 规范化配置可配置验证失败时是否默认只显示验证错误的首个消息
SingleValidationErrorDisplay4.9.3.9 ⏱️2024.05.21 a7b8000 -
JSON序列化支持设置DateOnly和TimeOnly类型格式化 4.9.3.9 ⏱️2024.05.21 #I9QZKQ - 互联网用户名数据验证
ValidationTypes.Username4.9.3.8 ⏱️2024.05.21 b77d0a0 -
PBKDF2加密和比较功能的静态类和字符串扩展支持 4.9.3.7 ⏱️2024.05.21 0d645d2 - 定时任务作业计划(含构建器)获取作业触发器数量
TriggerCount属性 4.9.3.6 ⏱️2024.05.20 f9cb042 -
[FlexibleArray]模型绑定特性,解决URL地址传递数组类型参数问题 4.9.3.5 ⏱️2024.05.20 e891f0e - 规范化
Swagger支持[SwaggerIgnore]特性忽略导出 4.9.3.1 ⏱️2024.05.15 75252a9 - 规范化
Swagger的withProxy参数,解决二级虚拟目录部署或被代理出现404问题 4.9.3.1 ⏱️2024.05.15 #I9PIIA #I9PHI8 - 定时任务执行上下文
Mode属性,可标识作业触发器是定时触发还是手动触发 4.9.3.1 ⏱️2024.05.15 efe0739 01a4003 - 规范化
Swagger是否自动加载Xml注释文件配置EnableXmlComments4.9.3.1 ⏱️2024.05.15 d01bbaa - 规范化结果支持拦截
JWT授权出现代码异常 4.9.3 ⏱️2024.05.10 52d3c2c edc51f4 - 定时任务支持立即执行触发特定作业下的特定触发器 4.9.3 ⏱️2024.05.10 3d83342
- 日志模块设置上下文支持无限极嵌套 4.9.3 ⏱️2024.05.10 0e313d2
- 扩展
- 突破性变化
查看变化
规范化接口 IUnifyResultProvider 添加了一个新的方法 OnAuthorizeException。此方法允许在 JWT 授权过程中出现异常时,提供统一的异常处理逻辑。
public interface IUnifyResultProvider
{
+ /// <summary>
+ /// JWT 授权异常返回值
+ /// </summary>
+ /// <param name="context">HttpContext 上下文</param>
+ /// <param name="metadata">异常元数据</param>
+ /// <returns></returns>
+ IActionResult OnAuthorizeException(DefaultHttpContext context, ExceptionMetadata metadata);
// ...其他代码
}
实现代码:
[UnifyModel(typeof(YourRESTfulResult<>))]
public class YourRESTfulResultProvider : IUnifyResultProvider
{
+ /// <summary>
+ /// JWT 授权异常返回值
+ /// </summary>
+ /// <param name="context">HttpContext 上下文</param>
+ /// <param name="metadata">异常元数据</param>
+ /// <returns></returns>
+ public IActionResult OnAuthorizeException(DefaultHttpContext context, ExceptionMetadata metadata)
+ {
+ return new JsonResult(RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)
+ , UnifyContext.GetSerializerSettings(context));
+ }
// ...其他代码
}
查看变化
修改了 AppAuthorizeHandler 中的 HandleAsync 方法签名,增加了一个 DefaultHttpContext 类型的参数 httpContext。
- public override Task HandleAsync(AuthorizationHandlerContext context)
+ public override Task HandleAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
- 问题修复
- 规范化上下文处理中间件路由(无控制器情况)出现空异常问题 4.9.3.19 ⏱️2024.06.09 8f0968b
-
Swagger授权后出现客户端JavaScript错误 4.9.3.18 ⏱️2024.06.08 9efa94f - 项目名称包含数字且使用
<inheritdoc/>继承注释时,Swagger加载注释文件出现异常问题 4.9.3.17 ⏱️2024.06.04 857635d - 远程请求出现
HttpRequestException异常时HttpResponseMessage对象为空问题 4.9.3.15 ⏱️2024.06.04 8d5f30b - 定时任务因 f9cb042 提交导致的异常 4.9.3.13 ⏱️2024.05.28 da4e6fb #I9SPOL
- 数据验证校验
Username正则表达式长度错误问题 4.9.3.10 ⏱️2024.05.23 0277555 - 远程请求不支持通过
SetHeaders设置请求内容头信息 4.9.3.6 ⏱️2024.05.20 #I9QLAY d43581f - 因升级
Swashbuckle.AspNetCore至6.6.1导致Swagger无法自动设置授权信息问题 4.9.3.4 ⏱️2024.05.16 c68f6c8 - 因升级
Swashbuckle.AspNetCore至6.6.1导致TypelnfoResolve异常问题 4.9.3.3 ⏱️2024.05.16 64860b2 Admin.NET - #I9PMXH
- 其他更改
- 文档
- 定时任务文档、规范化接口文档、数据加解密文档、安全授权文档、动态
WebAPI文档、发布桌面程序文档、数据验证文档、远程请求文档、本地化多语言文档
- 定时任务文档、规范化接口文档、数据加解密文档、安全授权文档、动态
v4.9.2(已发布)
v4.9.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I9CHX5 2024.03.28 ~ 2024.05.08 🆕
- 新特性
-
SHA1加密和比较功能的静态类和字符串扩展支持 4.9.2.41 ⏱️2024.05.08 @superbisu !879 f592757 - 定时任务看板可配置是否默认展开所有作业触发器
DefaultExpandAllJobs4.9.2.40 ⏱️2024.05.07 77c1e6f - 定时任务看板支持是否显示空触发器作业
DisplayEmptyTriggerJobs和是否显示页头DisplayHead4.9.2.39 ⏱️2024.05.07 f64d45f - 定时任务支持取消指定触发器正在执行的作业程序 4.9.2.38 ⏱️2024.05.07 5aa20b5
- 粘土对象
Clay转换为可枚举对象AsEnumerable()方法 4.9.2.37 ⏱️2024.05.06 b1c8fa4 - 远程请求支持返回
HttpResponseModel<T>类型,包含HttpResponseMessage、返回值等属性 4.9.2.34 ⏱️2024.04.30 42ccdaa - 定时任务作业计划支持根据触发器
Id集合做批量删除操作 4.9.2.33 ⏱️2024.04.30 d01a6e7 - 动态
WebAPI支持配置基元类型和字符串类型默认绑定信息 4.9.2.32 ⏱️2024.04.28 d7e7a02 - 支持检查作业信息额外数据的键是否定义
ContainsProperty(key)方法 4.9.2.32 ⏱️2024.04.28 71f97f0 - 日志模块
MessageProcess配置,可对日志消息进行额外处理,如敏感内容脱敏 4.9.2.32 ⏱️2024.04.28 0d9ff5e - 定时任务支持配置作业触发器
RunOnStart的处理逻辑options.RunOnStartProvider4.9.2.29 ⏱️2024.04.23 c9e0e3e -
EFCore批量更新支持设置includePropertyNames和excludePropertyNames参数 4.9.2.28 ⏱️2024.04.23 c9926cc - 远程请求代理模式支持
[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 -
AppSettings扩展程序集ExternalAssemblies配置支持目录扫描 4.9.2.14 ⏱️2024.04.10 e68f0a6 - 定时任务批量设置作业组名称
.GroupSet方法 4.9.2.9 ⏱️2024.04.09 9e08278 - 控制器/动态
WebAPI方法添加[DisplayName]特性生成Swagger文档注释 4.9.2.3 ⏱️2024.03.30 0f24c66 - 远程请求且出现异常时输出重试日志 4.9.2.1 ⏱️2024.03.29 e4549eb
- 定时任务启动时检查不合法的作业触发器配置并打印警告日志 4.9.2 ⏱️2024.03.28 3190f4c
-
- 突破性变化
-
DES加解密相关类和方法命名:DESCEncryption->DESEncryption,ToDESCEncrypt->ToDESEncrypt,ToDESCDecrypt->ToDESDecrypt4.9.2.41 ⏱️2024.05.08 a46f129 - 定时任务作业执行上下文
RunId类型,由Guid改为string类型 4.9.2.38 ⏱️2024.05.07 5aa20b5 -
Swagger文档注释逻辑,将///注释方式优先级调整至最高,可覆盖[DisplayName]特性方式 4.9.2.17 ⏱️2024.04.14 ba5249c - 定时任务作业计划工厂
TryRunJob方法签名,追加out IScheduler scheduler参数 4.9.2.16 ⏱️2024.04.11 89061ef
-
- 问题修复
- 任务队列在个别情况下出现出队同步阻塞问题 4.9.2.43 ⏱️2024.05.08 f595b47
- 定时任务看板点击作业信息列表的操作按钮也会触发展开/收缩作业触发器
bug4.9.2.40 ⏱️2024.05.07 77c1e6f - 模板引擎不支持将粘土对象或
DynamicObject派生类类型设置为模板数据 4.9.2.36 ⏱️2024.05.05 07ee172 - 启动时输出控制台日志配置
options.MessageProcess无效问题 4.9.2.36 ⏱️2024.05.05 b5cb0fe - 远程请求
HttpResponseModel<T>不支持重复读Response.Content流问题 4.9.2.35 ⏱️2024.04.30 7ca0650 - 审计日志
Monitor捕获异常时因其StackTrace堆栈信息可能为null引发的空异常问题 4.9.2.31 ⏱️2024.04.25 @xjj_0906 !875 7621e75 - 定时任务间隔触发器获取下一周期时间缺少了
RunOnStart和StartTime考虑场景 4.9.2.30 ⏱️2024.04.23 2595379 7ac6a54 - 定时任务看板作业触发器类型文字过多出现超出布局情况 4.9.2.29 ⏱️2024.04.23 f9dd33b
- 文件日志在一些特定情况下出现
The stream writer is currently in use by a previous write operation.异常 4.9.2.27 ⏱️2024.04.22 3ca012b - 定时任务毫秒级间隔触发器存在严重的误差问题 4.9.2.26 ⏱️2024.04.22 9c8210c
- 定时任务创建作业处理程序存在内存溢出风险 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 - 定时任务生成
PostgreSQL数据库SQL语句的字段名缺少"双引号 4.9.2.13 ⏱️2024.04.10 #I9FD9Y - 定时任务使用
JobBuilder构建委托作业永远无法执行问题 4.9.2.10 ⏱️2024.04.10 Sundial#I7KU7K - 规范化结果在未启用
401/403等状态码中间件时进行了错误拦截 4.9.2.8 ⏱️2024.04.08 b135e8c - 客户端设置
JWT Token时如果Bearer后面跟多个空格导致验证失败问题 4.9.2.8 ⏱️2024.04.08 @xuejf168 !874 -
SQL查询结果转模型不支持DateOnly和TimeOnly属性类型 4.9.2.7 ⏱️2024.04.04 31f9d23 - 粘土对象调整原先类型并设置混合类型异常问题 4.9.2.6 ⏱️2024.04.03 83b216f
- 粘土对象将
Object类型设置给Array类型出现递归死循环问题 4.9.2.5 ⏱️2024.04.03 1126c74 - 粘土对象不支持嵌套粘土对象问题 4.9.2.4 ⏱️2024.04.02 fcb1223
- 粘土对象序列化后出现二次序列化成字符串问题 4.9.2.4 ⏱️2024.04.02 fcb1223
- 在
.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
- 其他更改
- 文档
- 事件总线文档、定时任务文档、规范化接口文档、远程请求文档、粘土对象文档、
FS静态类文档、序列化文档、模块化文档、数据加解密文档、动态WebAPI文档、IPC通信模块文档、日志文档、安全授权文档
- 事件总线文档、定时任务文档、规范化接口文档、远程请求文档、粘土对象文档、
- 贡献者
v4.9.1(已发布,.NET8)
v4.9.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I8GHNK 2023.11.15 ~ 2024.03.27 🆕
⭐️ .NET8 升级指南:https://furion.net/docs/net7-to-net8 ⭐️
- 新特性
- 任务队列支持配置延迟队列是否立即执行一次 4.9.1.56 ⏱️2024.03.21 #I9AF54
- 事件总线支持事件处理程序执行结果订阅 4.9.1.47 ⏱️2024.03.13 f3028fa
-
JWT授权配置RequireExpirationTime属性,解决JWT过期时间不能大于13年问题 4.9.1.46 ⏱️2024.03.13 #I9840M - 脱敏词汇模块支持自定义嵌入文件词汇文件名 4.9.1.45 ⏱️2024.03.09 4ed72fc
- 脱敏词汇模块支持获取敏感词和所在位置 4.9.1.45 ⏱️2024.03.09 #I972P7
- 任务队列支持配置特定的任务采用并行还是串行的执行方式 4.9.1.38 ⏱️2024.03.07 a732c72
- 任务队列可传入自定义任务
TaskId4.9.1.38 ⏱️2024.03.07 a732c72 - 监听日志
Monitor支持显示服务端端口号 4.9.1.36 ⏱️2024.03.02 9280b6d - 监听日志
Monitor支持显示客户端(远程)NAT端口号 4.9.1.36 ⏱️2024.03.02 #I957SE - 监听日志
Monitor支持显示Web主机启动或监听的地址 4.9.1.36 ⏱️2024.03.02 #I94XR1 0e34172 -
.NET9脚手架 4.9.1.31 ⏱️2024.02.14 3c7a25b -
.NET8特有的Blazor Auto模式脚手架 4.9.1.28 ⏱️2024.02.02 67ea9ad - 任务队列支持分配任务
TaskId,管道分类Channel和OnExecuted事件订阅 4.9.1.28 ⏱️2024.01.31 1c27434 - 远程请求支持自动处理状态码
301、302和响应头带Location4.9.1.27 ⏱️2024.01.29 65aa221 - 事件总线支持配置处理程序只消费一次 4.9.1.24 ⏱️2024.01.19 dc882eb
- 任务队列支持配置重试次数、重试间隔 4.9.1.24 ⏱️2023.01.19 1c27434
- 监听日志
Monitor可配置序列化是否处理long转string4.9.1.23 ⏱️2023.01.16 #I8WDH9 -
HTTP响应报文头输出Furion版本 4.9.1.23 ⏱️2024.01.16 a4a49d6 - 任务队列支持配置
Concurrent串行执行 4.9.1.22 ⏱️2024.01.14 #I8VXFV -
Serve.RunAsync异步启动主机方法支持 4.9.1.21 ⏱️2024.01.12 #I8V0J8 -
Oops.Text(errorCode)静态方法,可根据错误码获取错误消息 4.9.1.18 ⏱️2024.01.08 f25125c - 定时任务
IJobPersistence持久化接口OnExecutionRecord方法实现作业运行记录持久化 4.9.1.16 ⏱️2024.01.01 4d4d492 - 定时任务作业调度计划
OnExecutionRecord事件,可监听作业运行记录 4.9.1.16 ⏱️2024.01.01 4d4d492 -
EFCore数据库操作EntityNotTenant和EntityBaseNotTenant实体基类 4.9.1.11 ⏱️2023.12.04 b62bfb1 - 控制台日志支持启动时同步
ConsoleFormatterExtendOptions配置 4.9.1.10 ⏱️2023.12.04 a96fe08 - 定时任务支持取消正在运行的作业程序 4.9.1.9 ⏱️2023.12.03 3cc9be0
-
JSON.IsValid(jsonString)判断JSON字符串有效性 4.9.1.8 ⏱️2023.11.30 22bc69b -
axios-utils.ts解析token信息导出方法 4.9.1.7 ⏱️2023.11.29 ae8c3e8 - 规范化处理自动过滤
SSE请求、文件请求、图片请求 4.9.1.6 ⏱️2023.11.22 #I8IP6D -
[AppDbContext]特性支持UseSnakeCaseNaming属性配置表名使用蛇形命名 4.9.1.5 ⏱️2023.11.20 #I8HGR2 !863 - 时间戳模型绑定器将时间戳转换为
DateTime/DateTimeOffset类型 4.9.1.5 ⏱️2023.11.20 df3053c -
Newtonsoft.Json自动将时间戳转换为DateTime/DateTimeOffset类型 4.9.1.3 ⏱️2023.11.17 78a589d -
System.Text.Json自动将时间戳转换为DateTime/DateTimeOffset类型 4.9.1.2 ⏱️2023.11.17 abd5196 -
IRepositoryFactory<TEntity, TDbContextLocator>仓储功能,解决在Blazor中使用EFCore问题 4.9.1.1 ⏱️2023.11.16 4285ec0 文档说明 - 补偿策略模块功能 4.9.1 ⏱️2023.11.15 【源码地址】 dfc63e7
- 突破性变化
- 定时任务持久化
IJobPersistence接口方法为异步方法 4.9.1.59 ⏱️2024.03.25 c6af42d - 数据库日志写入接口
IDatabaseLoggingWriter方法为异步WriteAsync4.9.1.58 ⏱️2024.03.24 98584b2 - 远程请求
[Method]AsStreamAsync返回值类型 4.9.1.44 ⏱️2024.03.08 ef03308 - 任务入队返回值类型,由
Guid改为object类型 4.9.1.38 ⏱️2024.03.07 a732c72 - 框架底层适配
.NET9.0预览版 4.9.1.31 ⏱️2024.02.14 3c7a25b - 事件总线支持配置处理程序只消费一次 4.9.1.24 ⏱️2024.01.19 dc882eb
- 监听日志默认不进行序列化
long转string处理 4.9.1.23 ⏱️2024.01.16 #I8WDH9 - 定时任务
IJobPersistence持久化接口OnExecutionRecord方法实现作业运行记录持久化 4.9.1.16 ⏱️2024.01.01 4d4d492 - 动态
WebAPI生成版本控制路由规则,版本分隔符默认由@调整为v4.9.1.14 ⏱️2023.12.14 7677d0f -
Serilog扩展包依赖至8.0.0版本,移除.NET8.0的IWebHostBuilder.UseSerilogDefault扩展方法 4.9.1.1 ⏱️2023.11.16 5ab3e43 - 框架底层适配
.NET8.0正式版 4.9.1 ⏱️2023.11.15 - 框架脚手架适配
.NET8.0正式版 4.9.1 ⏱️2023.11.15
- 定时任务持久化
- 问题修复
- 动态
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 - 因 d212e2b 提交导致动态创建
WebAPI实现插件化功能失效 4.9.1.55 ⏱️2024.03.20 #I9A59F a96d276 - 数据验证
ValiationTypes.Color不支持八位RGBA格式问题 4.9.1.54 ⏱️2024.03.19 ca0b660 - 不注册
AddJwt不能使用JWTEncryption.Encrypt方法问题 4.9.1.53 ⏱️2024.03.16 5882cf9 - 通过漏洞扫描工具扫描框架出现 CVE-2019-0820 高危漏洞 4.9.1.50 ⏱️2024.03.15 68056ec
-
ASP.NET Core启动时自动载入NuGet包导致模块化配置SupportPackageNamePrefixs出现非预期的结果 4.9.1.50 ⏱️2024.03.15 d212e2b - 动态
WebAPI配置了DefaultModule后导致生成重复的模块路由,由 87849d1 提交导致 4.9.1.49 ⏱️2024.03.14 #I98GDW - 在
Newtonsoft序列化中启用了AddLongTypeConverters配置来处理值类型被声明为可空类型并赋予默认值时出现转换异常问题 4.9.1.48 ⏱️2024.03.13 ecd547f - 脱敏词汇模块获取所有词汇没有去重问题 4.9.1.45 ⏱️2024.03.09 4ed72fc
- 定时任务设置作业触发器
RunOnStart在配置了StartTime属性后出现启动时机错误问题 4.9.1.42 ⏱️2024.03.08 c1e2eb3 - 定时任务设置作业触发器
StartTime后导致获取间隔触发器NextRunTime不正确问题 4.9.1.41 ⏱️2024.03.07 734a8c3 1756ab4 - 远程请求重试操作出现
The request message was already sent. Cannot send the same request message multiple times.异常 4.9.1.40 ⏱️2024.03.07 #I96MOY -
Web主机未启动但泛型主机已启动时使用App.GetService出现RootServices为null问题 4.9.1.37 ⏱️2024.03.03 ee70ab9 - 任务队列订阅任务执行结果处理程序中出现异常后重复触发问题 4.9.1.35 ⏱️2024.02.28 fa81c54
- 事件总线因
4.9.1.33(0bbeb49) 版本导致自定义事件存储器无法消费动态订阅器问题 4.9.1.34 ⏱️2024.02.27 d66175c - 模块化开发重复注册
Inject导致异常问题 4.9.1.32 ⏱️2024.02.21 1651013 -
DateTime/DateTimeOffset/DateOnly/TimeOnly默认格式配置无效问题 4.9.1.30 ⏱️2024.02.07 8057a6a - 远程请求解析不标准的响应头
charset设置导致异常问题 4.9.1.29 ⏱️2024.02.05 d5d03e5 -
throw Oops.Oh(message)在Blazor组件中使用出现空异常问题 4.9.1.28 ⏱️2024.01.31 cc5b84d - 动态
WebAPI设置VersionInFront: false异常问题 4.9.1.26 ⏱️2024.01.12 #I8ZGGH #I8ZDXD #I8ZFNG - 启用
WithStackFrame配置后可能出现空异常问题 4.9.1.21 ⏱️2024.01.12 c8be745 - 动态
WebAPI配置ForceWithRoutePrefix不包含Module问题 4.9.1.19 ⏱️2024.01.09 87849d1 - 规范化文档加载文档注释时如果存在类完全限定名一致出现重复键异常问题 4.9.1.17 ⏱️2024.01.04 #I8TJZ0
- 动态
WebAPI因 1dc7ea7 提交导致AsLowerCamelCase配置失效问题 4.9.1.15 ⏱️2023.12.20 d9810be - 粘土对象转换成
Dictionary对象不支持递归问题 4.9.1.13 ⏱️2023.12.11 #I8NFT4 -
Scoped.CreateAsync内部异常上层应用不能捕获问题 4.9.1.12 ⏱️2023.12.08 0a89a43 -
Scoped.CreateUowAsync内部异常上层应用不能捕获问题 4.9.1.8 ⏱️2023.11.30 3c859e8 - 定时任务设置触发器
Result后作业执行异常不能重置问题 4.9.1.7 ⏱️2023.11.24 147215f -
JWTEncryption.GetJWTSettings()独立使用时无法获取自定义配置 4.9.1.4 ⏱️2023.11.18 c045e08
- 动态
- 其他更改
- 任务队列
concurrent类型定义,由object调整为bool?4.9.1.57 ⏱️2024.03.22 cebb48d - 远程请求核心类型
HttpRequestMessage和HttpResponseMessage对象创建和销毁方式 4.9.1.43 ⏱️2024.03.08 03034c9 - 事件总线在超高频事件中内存占用(约
9%) 4.9.1.33 ⏱️2024.02.25 0bbeb49 - 定时任务
GC垃圾回收器回收时机,降低长时间内存占用 4.9.1.23 ⏱️2024.01.16 f43fc25 - 模板引擎编译性能,提升模板缓存解析速度 4.9.1.16 ⏱️2023.12.27 d7ea423
- 任务队列
- 文档
- ASP.NET 9 集成文档
- .NET8 升级.NET9 文档
-
Docker全新部署文档 -
Nginx部署文档 -
Windows Service部署文档 - 仓储文档、
Db静态类文档、脚手架文档、.NET7升级.NET8文档、JSON序列化文档、Docker部署文档、数据库上下文文档、虚拟文件文档、远程请求文档、HttpContext文档、JSON静态类文档、定时任务文档、数据库仓储扩展文档、数据库实体文档、规范化文档、任务队列文档、虚拟文件系统文档、PM2部署文档、事件总线文档
- 贡献者
- 丁 AS (@cnbdas) !872
- wangmin (@wangmin2659) !871
- 简简安 (@MadOneYou) !869 !870
- zuohuaijun (@zuohuaijun) !865
- anliuty (@anliuty) !863
- 风云明月 (@www.fengyunmy.com) !862
v4.8.8(已发布)
v4.8.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I6VF8V 2023.04.13 ~ 2023.11.09 🆕
- 新特性
-
Db.GetNewDbContext()多个重载方法,实现类似new DbContext()操作 4.8.8.55 ⏱️2023.11.09 4157629 - 控制台日志
AddConsoleFormatter服务支持WriteFilter属性过滤 4.8.8.52 ⏱️2023.11.07 516acb4 - 监听日志
LoggingMonitor支持打印输出requestHeaders请求头信息 4.8.8.50 ⏱️2023.10.27 #I8BHM3 - 多语言支持
L.GetDefaultCulture()获取本地配置默认语言 4.8.8.49 ⏱️2023.10.25 !858 - 定时任务
Http作业请求头Headers和作业分组Group和描述Description支持 4.8.8.46 ⏱️2023.10.09 #I85Z7S - 定时任务看板列表支持作业分组名排序 4.8.8.43 ⏱️2023.09.14 #I7YQ9V
- 验证特性
[DataValidation]支持[Display]和[DisplayName]特性设置{0}4.8.8.42 ⏱️2023.09.01 #I7XB3T - 监听日志
LoggingMonitor支持配置日志输出级别 4.8.8.41 ⏱️2023.08.25 #I7SRTP - 多语言支持
L.GetString(name, culture)获取指定区域翻译 4.8.8.41 ⏱️2023.08.04 044b0ed - 粘土对象
.ConvertTo支持自定义值提供器 4.8.8.40 ⏱️2023.08.03 70d5888 - 规范化文档枚举支持
[EnumToNumber]特性配置生成前端枚举定义代码是字符串值还是整数值类型,默认为字符串值 4.8.8.35 ⏱️2023.07.06 #I7IZ7S - 定时任务作业计划
OnChanged事件处理 4.8.8.29 ⏱️2023.06.25 e4c4cf1 -
Swagger分组信息可在任意配置文件中通过[openapi:分组名]进行配置 4.8.8.26 ⏱️2023.06.20 a70eed3 -
TP.WrapperRectangle绘制矩形日志模板 4.8.8.25 ⏱️2023.06.14 60ffd76 -
IServiceScope.CreateDefaultHttpContext扩展方法 4.8.8.24 ⏱️2023.06.07 11a55e1 - 配置模块
IgnoreConfigurationFiles支持完整的文件通配符 4.8.8.22 ⏱️2023.05.25 #I78ABL - 定时任务支持二级虚拟目录
VisualPath配置部署 4.8.8.20 ⏱️2023.05.18 #I740IA - 监听日志
LoggingMonitor支持Razor Pages4.8.8.16 ⏱️2023.05.15 #I7332C - 定时任务作业处理程序工厂
IJobFactory支持 4.8.8.13 ⏱️2023.05.08 ad58dd3 -
AES支持对文件(含超大文件)进行加解密 4.8.8.11 ⏱️2023.05.05 1d2265b - 动态
WebAPI支持text/plain格式的Body参数 4.8.8.9 ⏱️2023.05.04 b49fe50 - 插件化
IDynamicApiRuntimeChangeProvider接口,可在运行时动态添加WebAPI/Controller4.8.8.8 ⏱️2023.05.04 322ea59
-
查看变化
在一些特定的需求中,我们需要在运行时动态编译代码,如动态编写 WebAPI,之后能够在不重启主机服务的情况下即可有效。比如这里动态添加 SomeClass 动态 WebAPI,然后在 Swagger/路由系统 中立即有效:
using Furion;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace YourProject.Application;
public class PluginApiServices : IDynamicApiController
{
private readonly IDynamicApiRuntimeChangeProvider _provider;
public PluginApiServices(IDynamicApiRuntimeChangeProvider provider)
{
_provider = provider;
}
/// <summary>
/// 动态添加 WebAPI/Controller
/// </summary>
/// <param name="csharpCode"></param>
/// <param name="assemblyName">可自行指定程序集名称</param>
/// <returns></returns>
public string Compile([FromBody] string csharpCode, [FromQuery] string assemblyName = default)
{
// 编译 C# 代码并返回动态程序集
var dynamicAssembly = App.CompileCSharpClassCode(csharpCode, assemblyName);
// 将程序集添加进动态 WebAPI 应用部件
_provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
// 返回动态程序集名称
return dynamicAssembly.GetName().Name;
}
/// <summary>
/// 移除动态程序集 WebAPI/Controller
/// </summary>
public void Remove(string assemblyName)
{
_provider.RemoveAssembliesWithNotifyChanges(assemblyName);
}
}
这时只需要请求 api/plugin-api/compile 接口同时设置请求 Content-Type 为 text/plain,接下来传入 C# 代码字符串 即可,如:
using Furion.DynamicApiController;
namespace YourProject.Application;
public class SomeClass : IDynamicApiController
{
public string GetName()
{
return nameof(Furion);
}
}

之后刷新浏览器即可看到最新的 API:

还可以在运行时动态卸载,使用 DELETE 请求 api/plugin-api 即可。
-
- 定时任务
Schedular.CompileCSharpClassCode(code)支持动态编译作业处理程序代码 4.8.8.7 ⏱️2023.04.30 fe1e8a1
- 定时任务
-
-
App.CompileCSharpClassCode(code)动态编译类定义代码 4.8.8.7 ⏱️2023.04.30 fe1e8a1
-
-
- 粘土对象支持结构
struct对象类型 4.8.8.7 ⏱️2023.04.30 a0fa3aa
- 粘土对象支持结构
-
- 定时任务支持配置
IJob执行异常FallbackAsync回退策略 4.8.8.6 ⏱️2023.04.25 7671489
- 定时任务支持配置
-
- 定时任务支持在非
IOC/DI项目类型中使用 4.8.8.5 ⏱️2023.04.24 #I6YJNB
- 定时任务支持在非
-
-
RSA支持对超长字符(超245位)进行分段加解密 4.8.8.2 ⏱️2023.04.19 !788 感谢 @YaChengMu
-
-
-
System.Text.Json和Newtonsoft.Json对粘土对象Clay支持 4.8.8.1 ⏱️2023.04.18 #I6WKRZ
-
-
- 粘土对象可反射转换成特定
IEnumerable<T>类型:clay.ConvertTo<T>()4.8.8 ⏱️2023.04.13 5d54a65
- 粘土对象可反射转换成特定
-
-
Serve.IdleHost支持返回http和https协议Web地址(端口) 4.8.8 ⏱️2023.04.13 fdf7885
-
- 突破性变化
- 定时任务看板
SyncRate配置,前后端采用最新的SSE推送技术替代 4.8.8.29 ⏱️2023.06.25 e4c4cf1 - 监听日志
WriteFilter和ConfigureLogger的ActionExecutingContext和ActionExecutedContext类型为FilterContext4.8.8.16 ⏱️2023.05.15 #I7332C -
IJsonSerializerProvider序列化接口,添加Deserialize反序列化方法 4.8.8.15 ⏱️2023.05.15 !815 感谢 @YaChengMu
- 定时任务看板
查看变化
添加 25-32行 接口方法:
namespace Furion.JsonSerialization;
/// <summary>
/// Json 序列化提供器
/// </summary>
public interface IJsonSerializerProvider
{
/// <summary>
/// 序列化对象
/// </summary>
/// <param name="value"></param>
/// <param name="jsonSerializerOptions"></param>
/// <returns></returns>
string Serialize(object value, object jsonSerializerOptions = default);
/// <summary>
/// 反序列化字符串
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="json"></param>
/// <param name="jsonSerializerOptions"></param>
/// <returns></returns>
T Deserialize<T>(string json, object jsonSerializerOptions = default);
/// <summary>
/// 反序列化字符串
/// </summary>
/// <param name="json"></param>
/// <param name="returnType"></param>
/// <param name="jsonSerializerOptions"></param>
/// <returns></returns>
object Deserialize(string json, Type returnType, object jsonSerializerOptions = default);
/// <summary>
/// 返回读取全局配置的 JSON 选项
/// </summary>
/// <returns></returns>
object GetSerializerOptions();
}
如果使用 Newtonsoft.Json 则只需添加以下实现即可:
/// <summary>
/// 反序列化字符串
/// </summary>
/// <param name="json"></param>
/// <param name="returnType"></param>
/// <param name="jsonSerializerOptions"></param>
/// <returns></returns>
public object Deserialize(string json, Type returnType, object jsonSerializerOptions = null)
{
return JsonConvert.DeserializeObject(json, returnType, (jsonSerializerOptions ?? GetSerializerOptions()) as JsonSerializerSettings);
}
- 问题修复
- 远程请求获取响应
Cookies被截断问题 4.8.8.54 ⏱️2023.11.08 #I8EV1Z - 远程请求上传文件在其他编程语言获取文件名存在双引号问题 4.8.8.53 ⏱️2023.11.07 #I8EF1S
- 定时任务高频作业下持久化操作出现阻塞卡问题 4.8.8.51 ⏱️2023.11.06 f1d0b4a
- 定时任务看板中间件
SSE请求不是长连接导致连接频繁初始化销毁 4.8.8.49 ⏱️2023.10.26 1997f1b - 动态
WebAPI不能正确移除AppService命名的Service问题 4.8.8.47 ⏱️2023.10.10 #I86NL - 审计日志不支持
dynamic/JsonElement序列化问题 4.8.8.45 ⏱️2023.09.29 #I84SD5 -
Scoped.CreateUowAsync作用域工作单元异常无法回滚问题 4.8.8.44 ⏱️2023.09.23 #I833I9 - 模板引擎高并发读取缓存模板出现线程占用问题 4.8.8.43 ⏱️2023.09.14 #I80ZKB
- 使用刷新
Token也能通过鉴权检查严重安全Bug4.8.8.42 ⏱️2023.08.28 #I7TII4 - 粘土对象不支持枚举类型问题 4.8.8.41 ⏱️2023.08.25 #I7VDDL
- 定时任务因上一版本修改 4e2615b 导致自定义作业触发器异常问题 4.8.8.36 ⏱️2023.07.06 #I7J59D
- 审计日志解析
DateTime类型参数不是本地时间问题 4.8.8.33 ⏱️2023.06.29 #I7GW32 - 定时任务因上一版本修改 4e2615b 导致
Cron解析异常问题 4.8.8.32 ⏱️2023.06.28 #I7GQ5I - 定时任务设置额外数据不支持
long/int64类型参数问题 4.8.8.31 ⏱️2023.06.28 4e2615b - 定时任务休眠毫秒数大于
int.MaxValue时出现ArgumentOutOfRangeException4.8.8.27 ⏱️2023.06.21 #I7F6ZT -
Cron表达式步长解析器错误 4.8.8.25 ⏱️2023.06.14 #I7D9XU - 修复
ExpandoObject.ToDictionary()转换异常 4.8.8.25 ⏱️2023.06.14 #I7BY0P - 配置友好异常
FriendlyExceptionSettings:DefaultErrorMessage无效问题 4.8.8.23 ⏱️2023.05.31 #I79LIG -
Swagger进行分组后Tags不能进行分组过滤问题 4.8.8.22 ⏱️2023.05.25 #I78A55 - 因 9d8cb82 代码提交导致命名服务解析异常问题 4.8.8.21 ⏱️2023.05.18 #I76JZR
- 因 9d8cb82 代码提交导致服务
AOP异常拦截问题 4.8.8.17 ⏱️2023.05.15 #I73A8E - 动态
WebAPI自定义路由模板参数和自动拼接参数冲突问题 4.8.8.15 ⏱️2023.05.15 #I72ZZ2 - 远程请求在被请求端返回非
200状态码但实际请求已处理也抛异常问题 4.8.8.14 ⏱️2023.05.12 b14a51f -
App.CompileCSharpClassCode(code)运行时添加匿名程序集编译异常问题 4.8.8.8 ⏱️2023.05.04 322ea59 -
LoggingMonitor打印泛型类型如果存在多个泛型参数问题 4.8.8.8 ⏱️2023.05.04 8d9cb74 - 脱敏处理如果字典存在重复词导致异常问题 4.8.8.4 ⏱️2023.04.23 #I6Y19K
- 远程请求
Body参数为粘土对象Clay类型序列化有误 4.8.8.1 ⏱️2023.04.18 #I6WKRZ -
Serve.IdleHost获取随机端口的本地地址带$符号问题 4.8.8 ⏱️2023.04.13 ed6f292
- 远程请求获取响应
- 其他更改
-
[UnitofWork]支持在Class中指定,解决Pages应用警告问题 4.8.8.42 ⏱️2023.09.01 #I7X51E - 取消远程请求
GET/HEAD不能传递Body的限制 4.8.8.39 ⏱️2023.08.02 8113460 - 规范化文档枚举生成
json格式,由int32改为string4.8.8.34 ⏱️2023.07.02 #I7HOPR - 规范化文档默认
Title解析规则,不再自动添加空格 4.8.8.26 ⏱️2023.06.20 24b7a47 - 组件
Component模式支持[DependsOn]支持继承 4.8.8.16 ⏱️2023.05.15 #I733RF - 定时任务
GC回收逻辑,避免高频添加作业导致尾延迟问题 4.8.8.3 ⏱️2023.04.21 #I6XIV8 - 定时任务日志设计,减少不必要的日志输出 4.8.8.3 ⏱️2023.04.21 #I6XI2L
-
- 文档
-
Jwt身份验证过程监听文档 - 事件总线
Redis集成文档 - 粘土对象文档、虚拟文件系统文档、序列化文档、事件总线文档、远程请求文档、数据加密文档、安全授权文档、动态
WebAPI文档、定时任务文档、JSON序列化文档、App静态类文档、规范化文档、配置文档、数据库上下文文档、Db静态类文档
-
- 贡献者
- Axin (@lfuxin) !858
- 陶泥 (@ncs48620) !848
- handsome_by (@handsomeboyyl) !842
- 拉风的 CC (@LFDCC) !841
- Felix Hoi (@felixhoi) !839
- zetaluoxin (@zetaluoxin) !834
- SongXinXin (@goodsxx) !832 !833
- 阿炬 (@quejuwen) !813
- KaneLeung (@KaneLeung) !808
- 蒋状先生 (@JiangZhuangXianSheng) !806 !853
- NeoLu (@neolu) !804
- 蓝色天空 (@lds2013) !796
- YaChengMu (@YaChengMu) !788 !815
v4.8.7(已发布)
🚀🎉🔥 2023 年 02 月 22 日,微软发布了.NET8 首个预览版。
https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-1/
Furion 第一时间完成了适配,v4 版本开始一套代码支持 .NET5-.NET8/N,支持所有 Furion 版本升级。
v4.8.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I6GVN8 2023.02.22
- 新特性
- 定时任务看板支持自定义刷新频率
SyncRate功能 4.8.7.43 ⏱️2023.04.12 703b465 -
Serve.GetIdleHost([host])静态方法,可获取一个指定主机的Web地址(端口) 4.8.7.43 ⏱️2023.04.12 fdf788 - 粘土对象可配置访问不存在
Key时是抛异常还是返回null4.8.7.40 ⏱️2023.04.10 e994d53 - 定时任务看板支持完全自定义
RequestPath入口地址功能 4.8.7.34 ⏱️2023.04.04 24736f6 -
App.GetServices(type)和App.GetServices<T>()获取服务实例集合 4.8.7.33 ⏱️2023.04.03 c3e9957 - 远程请求
[HttpMethod]ToSaveAsync下载远程文件并保存到磁盘方法 4.8.7.32 ⏱️2023.04.02 bfd02c1 - 定时任务一系列
.AlterTo修改作业触发器触发时间便捷方法 4.8.7.31 ⏱️2023.03.31 0349017 - 多语言支持
DateTime时间格式化配置节点DateTimeFormatCulture4.8.7.31 ⏱️2023.03.31 #I6RUOU -
Serve.IdleHost静态属性,可获取一个随机空闲Web主机地址(端口) 4.8.7.29 ⏱️2023.03.30 e425063 -
WinForm/WPF静态方法Serve.RunNative()可配置是否启用Web主机功能 4.8.7.26 ⏱️2023.03.29 #I6R97L -
WinForm/WPF支持依赖注入的Native.CreateInstance<T>()静态方法 4.8.7.23 ⏱️2023.03.27 53d51c3 -
WinForm/WPF快速注册静态方法:Serve.RunNative()4.8.7.23 ⏱️2023.03.27 53d51c3 - 远程请求支持
Content-Type为text/html和text/plain处理 4.8.7.22 ⏱️2023.03.27 #I6QMLR - 粘土对象可转换成
IEnumerable<T>对象并实现Lambda/Linq操作 4.8.7.19 ⏱️2023.03.22 2b14ed9
- 定时任务看板支持自定义刷新频率
查看变化
dynamic clay = Clay.Parse("{\"Foo\":\"json\",\"Bar\":100,\"Nest\":{\"Foobar\":true},\"Arr\":[\"NOR\",\"XOR\"]}");
// 将 clay.Arr 转换成 IEnumerable<dynamic>
IEnumerable<dynamic> query = clay.Arr.AsEnumerator<dynamic>();
// 实现 Lambda/Linq 操作
var result = query.Where(u => u.StartsWith("N"))
.Select(u => new
{
Name = u
})
.ToList();
-
-
Crontab.IsValid(...)静态方法,判断Cron表达式是否有效 4.8.7.17 ⏱️2023.03.20 #I6OHO4
-
-
- 日志配置
WithStackFrame,可控制是否输出产生日志的程序集,类型和具体方法 4.8.7.16 ⏱️2023.03.19 5ad6ae2
- 日志配置
查看变化
启用 WithStackFrame 日志配置后,可输出程序集,类型,方法签名信息。
// 控制台日志
services.AddConsoleFormatter(options =>
{
options.WithStackFrame = true;
});
// 文件日志
services.AddFileLogging(options =>
{
options.WithStackFrame = true;
});
// 数据库日志
services.AddDatabaseLogging(options =>
{
options.WithStackFrame = true;
});
日志输出如下:
info: 2023-03-17 18:25:06.7988349 +08:00 星期五 L System.Logging.EventBusService[0] #1
[Furion.dll] async Task Furion.EventBus.EventBusHostedService.ExecuteAsync(CancellationToken stoppingToken)
EventBus hosted service is running.
info: 2023-03-17 18:25:08.1393952 +08:00 星期五 L Microsoft.Hosting.Lifetime[14] #1
[System.Private.CoreLib.dll] void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine>(ref TStateMachine stateMachine)
Now listening on: https://localhost:5001
info: 2023-03-17 18:25:08.1620391 +08:00 星期五 L Microsoft.Hosting.Lifetime[14] #1
[System.Private.CoreLib.dll] void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine>(ref TStateMachine stateMachine)
Now listening on: http://localhost:5000
info: 2023-03-17 18:25:08.1972456 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1
[Microsoft.Extensions.Hosting.dll] void Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted()
Application started. Press Ctrl+C to shut down.
info: 2023-03-17 18:25:08.2456579 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1
[Microsoft.Extensions.Hosting.dll] void Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted()
Hosting environment: Development
info: 2023-03-17 18:25:08.2746134 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1
[System.Private.CoreLib.dll] void System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(bool throwOnFirstException)
Content root path: D:\Workplaces\OpenSources\Furion\samples\Furion.Web.Entry
info: 2023-03-17 18:25:18.1917784 +08:00 星期五 L Furion.Application.TestLoggerServices[0] #16
[Furion.Application.dll] void Furion.Application.TestLoggerServices.测试日志()
我是一个日志 20
这样就清楚地知道日志是哪个程序集、哪个类型、哪个方法输出的了。
-
- 定时任务作业计划/工厂立即执行
RunJob方法 4.8.7.11 ⏱️2023.03.15 #I6LD9X
- 定时任务作业计划/工厂立即执行
-
- 定时任务看板
UI提供立即执行功能 4.8.7.11 ⏱️2023.03.15 #I6LD9X
- 定时任务看板
-
- 远程请求
HttpRequestMessage扩展方法AppendHeaders4.8.7.10 ⏱️2023.03.14 #I6MVHT
- 远程请求
-
- 定时任务作业执行上下文
JobExecutionContext服务提供器ServiceProvider属性 4.8.7.10 ⏱️2023.03.14 02586f8
- 定时任务作业执行上下文
-
- 定时任务
HTTP作业,支持定时请求互联网URL地址 4.8.7.7 ⏱️2023.03.11 01d4466
- 定时任务
查看变化
services.AddSchedule(options =>
{
options.AddHttpJob(request =>
{
request.RequestUri = "https://www.chinadot.net";
request.HttpMethod = HttpMethod.Get;
// request.Body = "{}"; // 设置请求报文体
}, Triggers.PeriodSeconds(5));
});
-
- 定时任务作业触发器
Trigger执行结果Result和执行耗时ElapsedTime属性 4.8.7.7 ⏱️2023.03.11 01d4466
- 定时任务作业触发器
-
- 定时任务作业看板支持查看作业触发器执行结果
Result和执行耗时ElapsedTime属性 4.8.7.7 ⏱️2023.03.11 01d4466
- 定时任务作业看板支持查看作业触发器执行结果
-
- 定时任务休眠时长和唤醒时机日志输出 4.8.7.6 ⏱️2023.03.08 #I6LANE
-
-
Sql高级拦截支持返回IEnumerable<T>和T[]类型值 4.8.7.5 ⏱️2023.03.07 f2ca2d3
-
查看变化
过去版本如果返回对象类型只支持 List<T>,T 和 Tuple<>,现已支持 IEnumerable<T>、T[] 和 Tuple<> 混合体。
public interface ISql : ISqlDispatchProxy
{
[SqlExecute("select * from person")]
Person[] GetPersons();
[SqlExecute("select * from person")]
IEnumerable<Person> GetPersons2();
// 更复杂的组合
[SqlExecute(@"
select * from person where id = 1;
select * from person;
select * from person where id > 0;
select * from person where id > 0;
")]
(Person, List<Person>, Person[], IEnumerable<Person>) GetPersons();
}
-
-
.m3u8和.ts文件类型MIME支持 4.8.7.5 ⏱️2023.03.07 #I6KKEM
-
-
- 审计日志
LoggingMonitor支持对参数贴[SuppressMonitor]特性跳过记录 4.8.7.3 ⏱️2023.03.01 #I6IVGW
- 审计日志
-
- 审计日志
LoggingMonitor监听TraceId、ThreadId、Accept-Language4.8.7.1 ⏱️2023.02.27 df35201
- 审计日志
-
- 规范化结果
UnifyContext.GetSerializerSettings(string)静态方法 4.8.7.1 ⏱️2023.02.27 #I6HM7T
- 规范化结果
- 突破性变化
- 定时任务动态作业
DynamicJob委托/方法签名 4.8.7.10 ⏱️2023.03.14 6d56b53
- 定时任务动态作业
查看变化
减少记忆负担,统一动态作业和普通作业的 ExecuteAsync 方法签名,故做出调整。
由:
options.AddJob((serviceProvider, context, stoppingToken) =>
{
serviceProvider.GetLogger().LogInformation($"{context}");
return Task.CompletedTask;
}, Triggers.PeriodSeconds(5));
调整为:
options.AddJob((context, stoppingToken) =>
{
context.ServiceProvider.GetLogger().LogInformation($"{context}");
return Task.CompletedTask;
}, Triggers.PeriodSeconds(5));
-
- 适配
.NET8 Preview.14.8.7 ⏱️2023.02.22
- 适配
-
- 脚手架支持创建
.NET8 Preview.1项目 4.8.7 ⏱️2023.02.22
- 脚手架支持创建
- 问题修复
- 远程请求获取
Cookies时如果包含相同Key异常问题 4.8.7.44 ⏱️2023.04.12 #I6V3T7 - 粘土对象转换为
Dictionary<string, object>类型异常 4.8.7.41 ⏱️2023.04.11 f96baeb -
TP.Wrapper静态类不能准确识别多行内容问题 4.8.7.40 ⏱️2023.04.10 #I6UAC8 - 粘土对象不支持运行时动态设置携带特殊字符的
Key键 4.8.7.39 ⏱️2023.04.10 6572515 - 视图引擎模型为匿名泛型集合类型时出现类型转换异常 4.8.7.38 ⏱️2023.04.07 !773
- 定时任务通过作业
Id删除作业不能删除作业触发器问题 4.8.7.35 ⏱️2023.04.05 312ca35 - 动态
WebAPI去除叠词类型命名如ServiceService前后缀异常问题 4.8.7.32 ⏱️2023.04.02 #I6SB3Z - 因
4.8.7.22版本导致动态WebAPI类型注释丢失问题 4.8.7.27 ⏱️2023.03.29 #I6QM23 - 粘土对象遍历对象键值对因
4.8.7.19版本更新导致异常 4.8.7.25 ⏱️2023.03.28 #I6R4ZU -
Swagger UI不显示ControllerBase派生类注释 4.8.7.22 ⏱️2023.03.27 #I6QM23 - 日志输出
JSON格式漏掉了UseUtcTimestamp和TraceId键值 4.8.7.21 ⏱️2023.03.27 5c90e65 - 启用规范化结果后导致
WebSocket连接断开时出现异常 4.8.7.20 ⏱️2023.03.23 #I6PI5E - 定时任务作业状态为
积压:0和归档:6时调用立即执行后不能恢复上一次状态 4.8.7.18 ⏱️2023.03.21 6f5aae8 - 使用达梦数据库执行
sql不能自动修复命令参数前缀 4.8.7.18 ⏱️2023.03.21 #I6OK4T -
Cron表达式*符号解析器不够严谨,如:*1111aaaaa也被解析为*4.8.7.17 ⏱️2023.03.20 #I6OHO4 - 定时任务更新作业
null值默认被跳过问题 4.8.7.17 ⏱️2023.03.20 #I6OHO4 - 视图引擎不支持强制转换的
(object)model类型 4.8.7.16 ⏱️2023.03.19 #I6O3BD - 启用请求
Body重复读且在授权之前读取导致非GET/HEAD/OPTION请求异常 4.8.7.15 ⏱️2023.03.19 #I6NX9E - 定时任务生成
SQL语句没有处理'转义问题 4.8.7.15 ⏱️2023.03.19 #I6NXKA - 数据验证
ValiationTypes.GUID_OR_UUID不支持大写问题 4.8.7.14 ⏱️2023.03.16 #I6NP22 -
Blazor脚手架出现blazor.server.js不能加载问题(404) 4.8.7.13 ⏱️2023.03.16 #I6NOBQ - 定时任务服务在停止进程时会卡住
30秒问题 4.8.7.8 ⏱️2023.03.13 #I6MI9I #I6MHOU - 定时任务看板删除不存在的作业触发器出现空异常 4.8.7.7 ⏱️2023.03.11 01d4466
- 日志消息没有处理
\n换行符对齐问题 4.8.7.6 ⏱️2023.03.10 759bcc5 - 审计日志
LoggingMonitor对特定参数贴有[FromServices]特性依旧记录问题 4.8.7.3 ⏱️2023.03.01 17b134e -
Swagger接口排序同时指定Tag和Order之后无效 4.8.7.2 ⏱️2023.03.01 #I6IQDI #I6IP66
- 远程请求获取
- 其他更改
-
Blazor+WebAPI脚手架模板,默认添加授权支持 4.8.7.37 ⏱️2023.04.07 #I6OM8O 544f80d - 定时任务动态委托作业持久化逻辑,采用不触发持久化操作 4.8.7.36 ⏱️2023.04.06 7bb58b6
- 多语言中间件
app.UseAppLocalization()添加Action<options>委托参数 4.8.7.30 ⏱️2023.03.31 #I6RUOU - 定时任务
Http作业HttpMethod属性拼写错成HttpMedhod4.8.7.24 ⏱️2023.03.28 !756 - 粘土对象
number类型处理,若含.转double类型,否则转long类型 4.8.7.24 ⏱️2023.03.28 e82e883 - 视图引擎默认程序集,追加
System.Collections程序集 4.8.7.16 ⏱️2023.03.18 #I6O3BD - 定时任务配置选项
BuilSqlType属性命为BuildSqlType4.8.7.11 ⏱️2023.03.15 92117b8 - 定时任务查看作业触发器运行记录由保存
10条改为5条4.8.7.7 ⏱️2023.03.07 01d4466 - 脚手架模板,默认启用主流文件类型
MIME支持 4.8.7.5 ⏱️2023.03.07 e35cdab - 审计日志
LoggingMonitor返回值泛型字符串显示格式 4.8.7.1 ⏱️2023.02.27 df35201
-
- 文档
- 发布桌面程序 文档
- Native 全局静态类文档
- ASP.NET 8 集成 文档
- .NET7 升级.NET8 文档
- 定时任务文档、中间件文档、规范化结果文档、动态
WebAPI文档、日志记录文档、事件总线文档、虚拟文件系统文档、Sql高级代理文档、数据库实体文档、任务队列文档、跨域文档、配置选项文档、安全授权、脚手架文档、粘土对象文档、多语言文档
- 贡献者
- 柠檬苏打 (@lemon_soda) !778
- 拉风的 CC (@LFDCC) !773
- 吴伟烈 (@wuweilie) !772
- 缄默 (@alianyone) !765
- 写意 (@xjj_0906) !756
- lampon (@lampon) !740
- family520 (@family520) !739
- kingling (@kinglinglive) !732 !729
- ksmy (@ksmy) !731
- handsome_by (@handsomeboyyl) !727
v4.8.6(已发布)
v4.8.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I6DQ57 2023.02.08v4.8.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I6BC6J 2023.01.28
- 新特性
-
- 粘土对象支持任何字符作为
JSON/XML键 4.8.6.9 ⏱️2023.02.19 f99aee8 #note_16329657 - 动态
WebAPI自动检查路由是否包含重复参数,如果有自动修正而不是抛异常 4.8.6.5 ⏱️2023.02.17 5f15ea1
- 粘土对象支持任何字符作为
查看变化
在 Furion 4.8.6.5 之前,下列代码会抛出异常:The route parameter name 'roleid' appears more than one time in the route template.
原因是生成的路由包含了多个 {roleId}:/api/with-class/system/role/deptTree/{roleId}/{roleId}。
public class WithClass : IDynamicApiController
{
[HttpGet("system/role/deptTree/{roleId}")] // 过去版本抛异常,Furion 4.8.6.5+ 正常~
public string GetResult2(string roleId)
{
return nameof(Furion);
}
}
新版本 Furion 4.8.6.5+ 修正了该错误,自动移除后面重复的路由参数且不再抛异常,也就是最终生成路由为:/api/with-class/system/role/deptTree/{roleId}
-
-
byte[]类型MD5加密/比较重载方法 4.8.6.3 ⏱️2023.02.15 #I6F1NT
-
-
- 动态
WebAPI支持[RouteConstraint(":*")]路由约束 4.8.6.2 ⏱️2023.02.10 #I6E6JA
- 动态
-
-
Swagger启用登录后配置CheckUrl可获取本地存储的Authorization请求报文头 4.8.6.2 ⏱️2023.02.10 #I6E3LB
-
-
- 定时任务
IScheduler.[Try]UpdateDetail(builder => {})和IScheduler.[Try]UpdateTrigger(triggerId, builder => {})重载方法 4.8.6 ⏱️2023.02.08 6e43a54
- 定时任务
查看变化
- 更新作业信息
// 返回 ScheduleResult 类型
var scheduleResult = Scheduler.TryUpdateDetail(jobBuilder =>
{
jobBuilder.SetDescription("~~~");
}, out var jobDetail);
// 无返回值
scheduler.UpdateDetail(jobBuilder =>
{
jobBuilder.SetDescription("~~~");
});
- 更新作业触发器
// 返回 ScheduleResult 类型
var scheduleResult = scheduler.TryUpdateTrigger("triggerId", triggerBuilder =>
{
triggerBuilder.SetDescription("~~");
}, out var trigger);
// 无返回值
scheduler.UpdateTrigger("triggerId", triggerBuilder =>
{
triggerBuilder.SetDescription("~~");
});
-
- 审计日志
LoggingMonitor支持[DisplayName]特性解析和Title属性记录 4.8.5.10 ⏱️2023.02.07 #I6DHMF
- 审计日志
-
- 远程请求配置
SetHttpVersion(version)配置,可配置HTTP请求版本,默认为1.14.8.5.8 ⏱️2023.02.06 #I6D64H
- 远程请求配置
-
- 动态
WebAPI支持更加强大的路由组合功能 4.8.5.7 ⏱️2023.02.03 #I6CLPT
- 动态
查看变化
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace WebApplication38;
[Route("api/[controller]")]
[Route("api2/[controller]")]
public class Test1Service : IDynamicApiController
{
[HttpGet("test")]
[HttpPost]
[AcceptVerbs("PUT", "PATCH")]
public async Task GetTestName()
{
await Task.CompletedTask;
}
}
public class Test2Service : IDynamicApiController
{
[HttpGet("/root/test")]
[HttpGet("test")]
[HttpGet(Name = "other-test")]
[HttpGet("template-test", Name = "other-test")]
[HttpPost]
[AcceptVerbs("PUT", "PATCH")]
public async Task GetTestName()
{
await Task.CompletedTask;
}
}
[Route("api/[controller]")]
[Route("api2/[controller]/second")]
[Route("api3/[controller]/three")]
public class Test3Service : IDynamicApiController
{
[HttpGet]
[HttpGet("get/[action]")]
[HttpPost]
[HttpPost("post/cus-version")]
public string GetVersion()
{
return "1.0.0";
}
}

-
- 定时任务
Dashboard可自定义入口地址/schedule4.8.5.6 ⏱️2023.02.02 c5639f5
- 定时任务
-
-
App.GetServiceLifetime(type)获取服务注册生命周期类型 4.8.5.3 ⏱️2023.01.31 4a573a8
-
-
- 审计日志
LoggingMonitor记录HTTP响应状态码 4.8.5.2 ⏱️2023.01.30 abb4cbd
- 审计日志
-
- 定时任务执行上下文
RunId属性,用于标识单次作业触发器执行 4.8.5.1 ⏱️2023.01.30 1aac470
- 定时任务执行上下文
- 突破性变化
- 适配
.NET7.0.3和.NET6.0.144.8.6.3 ⏱️2023.02.15 eecbf83
- 适配
-
- 动态
WebAPI生成路由[HttpMethod(template)]规则 4.8.5.7 ⏱️2023.02.03 #I6CLPT
- 动态
查看变化
在过去,TestMethod 生成路由为:/mytest
// 注意这里没有 [Route] 特性
public class ClassService: IDynamicApiController
{
[HttpPost("mytest")]
public void TestMethod()
{
}
}
新版本:TestMethod 生成路由为:/api/class/mytest,TestMethod2 生成路由为:/mytest。
// 注意这里没有 [Route] 特性
public class ClassService: IDynamicApiController
{
[HttpPost("mytest")]
public void TestMethod()
{
}
[HttpPost("/mytest")]
public void TestMethod2()
{
}
}
也就是新版本如果不需要自动添加前缀,需在前面添加 /,旧版本不需要。
- 问题修复
查看变化
过去版本生成错误重复路由,如:api/system/SystemDictionary/api/system/SystemDictionary/Add,现已修正。
public class WithClass : IDynamicApiController
{
[Route("Add")]
public void Add()
{
}
[Route("Edit")]
public void Edit()
{
}
}
[Route("api/system/SystemDictionary")]
public class SystemService : WithClass
{
public void Some()
{
}
}
-
-
Serve.Run(urls: "端口")设置端口在.NET6/7下发布后始终是80端口问题 4.8.6.6 ⏱️2023.02.18 #I6G02W
-
-
- 粘土对象不支持
中文作为JSON/XML键问题 4.8.6.6 ⏱️2023.02.18 4961e01
- 粘土对象不支持
-
- 远程请求代理模式配置了
WithEncodeUrl = false无效问题 4.8.6.4 ⏱️2023.02.16 89639ba
- 远程请求代理模式配置了
-
- 动态
WebAPI自定义[HttpMethod(template)]之后生成错误路由 4.8.6.1 ⏱️2023.02.08 59fe53b
- 动态
-
-
优化远程请求ReadAsStringAsync底层方法,尝试修复Error while copying content to a stream.错误 4.8.5.8 ⏱️2023.02.06 #I6D64H
-
-
- 规范化结果不支持
OData协议控制器 4.8.5.5 ⏱️2023.02.01 !571
- 规范化结果不支持
-
- 在数据库日志的
IDatabaseLoggingWriter实现类中依赖注入ILogger<>导致死循环 4.8.5.4 ⏱️2023.02.01 #I6C6QU
- 在数据库日志的
-
-
Furion.Xunit/Furion.Pure.Xunit单元测试依赖注入单例服务时不是同一实例问题 4.8.5.3 ⏱️2023.01.31 305511e
-
-
- 数据库日志提供程序在应用程序终止时出现空异常问题 4.8.5 ⏱️2023.01.28 #I6AZ8Y
-
- 实体扩展方式操作数据库出现空异常问题 4.8.5 ⏱️2023.01.28 #I6AXU6
- 其他更改
- 文档
- 多语言
.json配置方式文档 - 日志文档、定时任务文档、动态
WebAPI文档,规范化结果文档,App静态类文档,Oops静态类文档、虚拟文件系统文档 !704,远程请求文档,序列化文档、入门文档、脱敏模块文档
- 多语言
- 贡献者
- Andy (@man119)
- liuhll (@liuhll2)
- 大柚 (@big-pomelo)
- WR_YT (@wr-yt)
v4.8.4(已发布,全新定时任务)
在过去两年,实现 Furion 从无到有,编写文档已逾三百万字,过程心酸开源人自知。
这一路日夜兼程,嘲讽批评常伴眼耳,即便辛苦无奈、想过放弃,但为了那微不足道的成就感依然努力着。
当然,也收获了不少... 越来越多拥趸者,越发精湛技术能力,更高层次思维模式,还有许多跨界跨行朋友。
在 《开源指北》中,我曾说道:“开源如同人的脸,好坏一面便知,缺点可能会受到嘲讽批评,优点也会收获赞扬尊重。别担心,他们正在塑造更好的你。”
.NET 要在国内真正发展起来,必须得有一些追逐梦想的人在做着不计付出的事情,而我希望自己能贡献一份微薄之力。所以,这一次重新起航,重塑 Furion 重塑自己。也许未来在某个 IT 圈但凡有人谈起 .NET 还能瞟到 Furion 的身影。
v4.8.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I68573 2022.12.30v4.8.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I657O5 2022.12.08v4.8.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I63CTP 2022.11.27v4.8.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I62RX3 2022.11.24v4.8.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I62NZV 2022.11.23
- 新特性
- 🎉 全新的定时任务模块 4.8.0 【查看源码】
- 🎉 全新的
Cron表达式模块 4.8.0 【查看源码】 - 🎉 全新的任务队列模块 4.8.3 【查看源码】
- 视图引擎支持无命名空间的强类型 4.8.4.16 ⏱️2023.01.15 #I6ABN3 #I6A7SI 076bb17
- 视图引擎支持匿名类型模型带集合类型属性
@foreach遍历 4.8.4.15 ⏱️2023.01.13 #I6A7SI -
Swagger支持复制路由地址功能 4.8.4.13 ⏱️2023.01.11 #I5VNJI - 动态
WebAPI方法支持通过[ActionName(名称)]和[HttpMethod(Name=名称)]指定路由名称 4.8.4.12 ⏱️2023.01.10 #I69AOJ f699540 -
BadPageResult.Status401Unauthorized等常见状态码401,403,404,500静态属性 4.8.4.11 ⏱️2023.01.09 #I69KQF -
crontab.GetSleepTimeSpan(baseTime)实例方法 4.8.4.10 ⏱️2023.01.09 #I69HM4 -
Enqueue/EnqueueAsync支持Cron表达式 实例重载方法 4.8.4.10 ⏱️2023.01.09 #I69HM4 -
*.bcmap和.properties文件类型MIME支持 4.8.4.9 ⏱️2023.01.06 !694 - 定时任务
Dashboard查看作业触发器最近运行记录功能 4.8.4.3 ⏱️2023.01.03 e7d24d8 - 定时任务作业触发器
trigger.GetTimelines()获取最近10条运行记录列表 4.8.4.3 ⏱️2023.01.03 e7d24d8 - 定时任务
Dashboard看板 4.8.4 ⏱️2022.12.30 d3f9669 - 定时任务
IScheduler.GetEnumerable()方法,可将作业计划转换成可枚举字典 4.8.4 ⏱️2022.12.30 4d5235c -
L.SetCurrentUICulture(culture)和L.GetCurrentUICulture()静态方法,可在运行时动态修改当前线程区域性 4.8.3.10 ⏱️2022.12.23 #I66JWA -
L.SetCulture(culture, immediately)方法重载,可配置运行时修改多语言立即有效 4.8.3.10 ⏱️2022.12.23 #I66JWA - 定时任务配置选项
options.JobDetail.LogEnabled配置,可自动输出执行日志 4.8.3.7 ⏱️2022.12.14 58d2c20 -
ValidationTypes更多常见验证格式(手机机身码类型,统一社会信用代码,GUID/UUID,base64) 4.8.3.6 ⏱️2022.12.13 3680d7a - 定时任务
IScheduler对象每次操作后自动刷新和提供手动刷新Reload()方法 4.8.3.3 ⏱️2022.12.09 #I65EQ1 - 定时任务间隔分钟作业触发器
Triggers.PeriodMinutes(5)和[PeriodMinutes(5)]特性 4.8.2.8 ⏱️2022.12.01 8e1f06f - 定时任务工作日作业触发器
Triggers.Workday()和[Workday]特性 4.8.2.6 ⏱️2022.11.30 28b2d20 - 定时任务作业校对功能,可对误差进行校正 4.8.2.6 ⏱️2022.11.30 f725a25
-
Crontab.ParseAt(..)静态方法 4.8.2.6 ⏱️2022.11.30 035cc23 -
Crontab所有Macro At静态方法 4.8.2.6 ⏱️2022.11.30 a15b69d -
Crontab.Workday表示周一至周五的Macro静态属性 4.8.2.6 ⏱️2022.11.30 a15b69d - 定时任务
Triggers所有带At的Cron表达式触发器构建器及特性 4.8.2.5 ⏱️2022.11.29 #I63PLR -
App.GetThreadId()和App.GetTraceId()获取线程Id和请求TraceId4.8.2.4 ⏱️2022.11.29 910fc1f -
App.GetExecutionTime(() => { /*Your Code*/ })获取代码执行耗时 4.8.2.4 ⏱️2022.11.29 5ab4b19 - 定时任务批量添加
SchedulerBuilder作业功能 4.8.2.4 ⏱️2022.11.29 5faa67b - 定时任务
BuildSqlType配置,可设置生成不同数据库类型的SQL语句 4.8.2.3 ⏱️2022.11.29 293f9bc !675 -
JobDetail和Trigger自定义ConvertToSQL输出SQL配置 4.8.2 ⏱️2022.11.27 0bb9d8f - 动态作业处理程序委托支持 4.8.1.8 ⏱️2022.11.27 e02266c
- 作业触发器
ResetOnlyOnce属性,支持只运行一次的作业重新启动服务重复执行 4.8.1.5 ⏱️2022.11.25 a8be728 - 事件总线支持简单的
Order编排规则 4.8.0 833c0d4 - 远程请求代理模式对于基元类型参数支持自动获取参数名 4.8.0 #I60OT6
- 动态
WebAPI自动识别方法的接口参数是否是服务,如果是自动添加[FromServices]特性 4.8.0 fae60a9 - 远程请求
[QueryString]特性添加时间格式化Format属性 4.8.1.2 !670 -
Serve.Run模式的.ConfigureServices方法 4.8.0 023391b -
Serve.RunGeneric通用泛型主机方法 4.8.0 6865f3d -
Serve.Run()的additional参数 4.8.0 023391b
查看变化
极速入门现在可以便捷注册服务,写测试例子的时候非常有用,无需编写 Startup.cs。
Serve.Run(additional: services =>
{
services.AddRemoteRequest();
});
// 通用泛型主机方式
Serve.RunGeneric(additional: services =>
{
services.AddRemoteRequest();
});
// 还可以省去 additional
Serve.Run(services =>
{
services.AddRemoteRequest();
});
// 通用泛型主机方式
Serve.RunGeneric(services =>
{
services.AddRemoteRequest();
});
-
-
Serve.Run主机返回值IHost4.8.0 #I61XHV
-
查看变化
在 Winfom/WPF 应用程序中,我们希望关闭窗体或退出应用程序时,能够关闭 Serve 主机:
using Microsoft.Extensions.Hosting;
public partial class App : Application
{
private readonly IHost _host;
public App()
{
_host = Serve.Run(silence: true);
}
protected override void OnExit(ExitEventArgs e)
{
_host.StopAsync();
_host.Dispose();
base.OnExit(e);
}
}
-
- 日志
JSON自动美化格式化器LoggerFormatter.JsonIndented4.8.0 7b9268c
- 日志
-
-
LoggingMonitor的JsonIndented配置,可配置是否美化JSON4.8.0 7b9268c
-
查看变化
默认情况下,配置输出 JSON 格式化 LoggerFormatter.Json 会浓缩到一行显示。
新版本支持 LoggerFormatter.JsonIndented 美化 JSON 配置:
// 控制台日志
services.AddConsoleFormatter(options =>
{
options.MessageFormat = LoggerFormatter.JsonIndented;
});
// 文件日志
services.AddFileLogging("mytemplate.log", options =>
{
options.MessageFormat = LoggerFormatter.JsonIndented;
});
// 数据库日志
services.AddDatabaseLogging<DatabaseLoggingWriter>(options =>
{
options.MessageFormat = LoggerFormatter.JsonIndented;
});
// LoggingMonitor 日志
services.AddMonitorLogging(options =>
{
options.JsonIndented = true;
});
-
- 日志模块是否输出
TraceId,同一个请求的日志TraceId一致 4.8.1.3 #I62VGG
- 日志模块是否输出
查看变化
在生产环境中,日志的输出是非常频繁的,但是很难从日志文件中判断哪些日志是属于同一个请求输出的,所以新增 WithTraceId 配置。
// 控制台日志
services.AddConsoleFormatter(options =>
{
options.WithTraceId = true;
});
// 文件日志
services.AddFileLogging("mytemplate.log", options =>
{
options.WithTraceId = true;
});
// 数据库日志
services.AddDatabaseLogging<DatabaseLoggingWriter>(options =>
{
options.WithTraceId = true;
});
输出日志如下:
info: 2022-11-24 14:34:55.1717549 +08:00 星期四 L System.Logging.EventBusService[0] #1
EventBus Hosted Service is running.
info: 2022-11-24 14:34:55.2504015 +08:00 星期四 L System.Logging.ScheduleService[0] #1
Schedule Hosted Service is running.
info: 2022-11-24 14:34:56.4280796 +08:00 星期四 L Microsoft.Hosting.Lifetime[14] #1
Now listening on: https://localhost:5001
info: 2022-11-24 14:34:56.4331170 +08:00 星期四 L Microsoft.Hosting.Lifetime[14] #1
Now listening on: http://localhost:5000
info: 2022-11-24 14:34:56.4384567 +08:00 星期四 L Microsoft.Hosting.Lifetime[0] #1
Application started. Press Ctrl+C to shut down.
info: 2022-11-24 14:34:56.4408766 +08:00 星期四 L Microsoft.Hosting.Lifetime[0] #1
Hosting environment: Development
info: 2022-11-24 14:34:56.4427659 +08:00 星期四 L Microsoft.Hosting.Lifetime[0] #1
Content root path: D:\Workplaces\OpenSources\Furion\samples\Furion.Web.Entry
info: 2022-11-24 14:35:06.8507338 +08:00 Thursday L Furion.Application.TestLoggerServices[0] #17 '00-48df9ac5c8280de2f301faa44a23a10c-b75678d9f3883b0b-00'
我是一个日志 20
info: 2022-11-24 14:35:16.0373384 +08:00 星期四 L Furion.Application.TestLoggerServices[0] #17 '00-ff4fb15d6ff41a0411784e66400f0dfd-962bc25eff788b25-00'
我是一个日志 20
- 突破性变化
- 问题修复
- 定时任务
StartAll出现个别作业显示无触发时间的状态 4.8.4.14 ⏱️2023.01.12 #I6A08X - 动态
WebAPI配置[Consumes]特性后Swagger不显示问题 4.8.4.12 ⏱️2023.01.10 daf25f8 - 定时任务停止作业触发器后运行记录不能写入最新记录问题 4.8.4.8 ⏱️2023.01.05 d4c553f
- 数据库日志注册在一些特殊情况下丢失日志上下文问题 4.8.4.6 ⏱️2023.01.04 #I68PDF
- 定时任务使用
Furion.Pure包访问Dashboard出现404问题 4.8.4.2 ⏱️2023.01.02 21977b7 - 在类中贴
[SuppressMonitor]特性但LoggingMonitor依然输出问题 4.8.4 ⏱️2022.12.30 #I6882I - 远程请求配置
WithEncodeUrl(false)对application/x-www-form-urlencoded请求类型无效 4.8.4 ⏱️2022.12.30 #I682DX -
LoggingMonitor序列化IQueryable<>或OData返回值类型出现死循环问题 4.8.3.4 ⏱️2022.12.10 7e8c9d0 - 定时任务通过
scheduler.RemoveTrigger(triggerId)报异常问题 4.8.3.3 ⏱️2022.12.09 #I65EQ1 - 定时任务作业触发器配置了
EndTime和StartTime之后Status没有对应上 4.8.3.1 ⏱️2022.12.09 52a5506 - 定时任务通过
scheduler.AddTrigger(triggerBuilder)无效的问题 4.8.3.1 ⏱️2022.12.09 #I65EQ1 - 作业拥有多个触发器时暂停作业后依然存在个别未暂停的清空(并发问题) 4.8.2.12 ⏱️2022.12.07 #I655W9
- 通过
Ctrl + C终止应用程序后获取TraceId出现对象已释放异常 4.8.1.12 ⏱️2022.12.07 55c3e49 -
cli.ps1脚本不支持EFCore 7.0问题 4.8.1.12 ⏱️2022.12.07 !676 -
EFCore实体监听器IEntityChangedListener问题 4.8.1.7 ⏱️2022.11.26 #I61CTI - 定时任务生成的
SQL语句不支持MySQL问题 4.8.1.7 ⏱️2022.11.26 #I638ZC - 运行时启动/暂停作业无效问题 4.8.1.6 ⏱️2022.11.25 #I6368M
- 作业触发器不符合下一次执行规律但
NextRunTime不为null情况 4.8.1.5 ⏱️2022.11.25 a8be728 - 从
.NET6/7降级回.NET5找不到.AddDateOnlyConverters()和.AddTimeOnlyConverters()扩展方法问题 4.8.0 cdddf8d -
Retry.InvokeAsync方法如果不传入fallbackPolicy参数报空异常问题 4.8.0 21af847 - 动态
WebAPI不支持在.NET7不声明[FromServices]自动注入问题 4.8.0 #I62HP1 - 远程请求
GetAsStreamAsync()报System.InvalidOperationException: Response Content-Length mismatch异常问题 4.8.1 #I62QY4 -
LoggingMonitor配置WriteFilter不起作用问题 4.8.1.2 #I62P52 90bcfda -
EFCore个别关系型数据库PostgreSQL/SqlServer/MySql出现短暂不能连接问题 4.8.1.3 2c530ef - 日志模块因
v4.8.0+版本导致写入数据库日志空异常问题 4.8.2.1 ⏱️2022.11.28 8d9d72b
- 定时任务
- 其他更改
- 文档
- 新版本定时任务文档
- Cron 表达式解析文档
- 任务队列文档
- Schedular 全局静态类文档
- TaskQueued 全局静态类文档
- 作业执行器实现超时文档 4.8.3.8 ⏱️2022.12.20
- 作业触发器
ResetOnlyOnce文档 4.8.1.5 ⏱️2022.11.25 a8be728 - 通过
Roslyn动态编译代码创建IJob类型文档 4.8.1.5 ⏱️2022.11.25 2c5e5be - 自定义
JobDetail和Trigger输出SQL文档 4.8.2 ⏱️2022.11.27 0bb9d8f - 远程请求
[QueryString]配置时间类型Format格式化文档 4.8.1.2 ⏱️2022.11.25 !673 -
Serve.Run()入门文档文档、安全授权文档、前端接口代理文档、事件总线文档、日志文档、Worker Service 文档、数据库实体触发器文档、App静态类文档、包管理工具文档
v4.7.9(已发布,.NET7)
🚀🎉🔥 2022 年 11 月 08 日,微软发布了.NET7 首个正式版。
Furion 第一时间完成了适配,v4 版本开始一套代码支持 .NET5-.NET7/N,支持所有 Furion 版本升级。
v4.7.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I60MFK 2022.11.11v4.7.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I60GZ8 2022.11.10v4.7.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I60591 2022.11.08v4.7.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I600R4 2022.11.08v4.7.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Z9TI 2022.11.03v4.7.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5YG48 2022.10.30v4.7.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Y6U3 2022.10.28v4.7.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Y04N 2022.10.27
- 新特性
- 日志模块时间格式化默认输出
毫秒部分,针对并发比较高的场景 4.7.0 c0dc36c - 写入数据库日志死循环输出检测机制 4.7.0 30dea0c
-
LoggingMonitor输出系统信息,.NET 架构和基础框架4.7.1 aeda902 - 远程请求
.SetQueries(obj, ignoreNullValue)重载方法 4.7.3 #I5Z8KC - 远程请求
.GetCookies()和.GetSetCookies()扩展方法 4.7.5 #I5ZY1L - 事件总线
.ReplaceStorerOrFallback自定义事件源存储器方法,可在自定义初始失败时回退到默认值 4.7.6 #I602NU -
LoggingMonitor输出启动信息,Cookies和请求端源信息 4.7.7 3037b04 -
JSON序列化DateOnly和TimeOnly类型转换器:.AddDateOnlyConverters()和.AddTimeOnlyConverters()4.7.9 !657 47a5fcb -
HttpContext.ReadBodyContentAsync()扩展方法重复读取Body内容 4.7.9 #I60IYU
- 日志模块时间格式化默认输出
- 突破性变化
- 所有脚手架支持
-f指定.NET版本 4.7.6 #I603AZ
- 所有脚手架支持
查看变化
# 创建 .NET5 版本
dotnet new furionapi -n 项目名称 -f net5
# 创建 .NET6 版本
dotnet new furionapi -n 项目名称 -f net6
# 创建 .NET7 版本
dotnet new furionapi -n 项目名称 -f net7
-
- 适配
.NET 6.0.11和.NET 74.7.5 7df3195
- 适配
-
- 所有脚手架至
.NET 74.7.5 7df3195
- 所有脚手架至
-
-
LogContext类型的所有方法至Furion.Logging命名空间下,解决空异常问题 4.7.3 #I5YOT3
-
查看变化
由:
var value = logContext.Get("Key"); // 过去如果 logContext == null 报错
改为:
using Furion.Logging;
var value = logContext.Get("Key"); // 新版本不会报错,且 value = null
-
- 旧版本定时任务为
弃用状态(一周内发布新版),如需取消警告在.csproj中添加<NoWarn>0618</NoWarn>4.7.9 0ff3ac0
- 旧版本定时任务为
- 问题修复
- 生成
JWT Token时间戳和自动刷新逻辑在高并发下检查有效性不够精确问题,原因是时间戳丢掉了毫秒部分 4.7.0 3c0c017 - 在
IDatabaseLoggingWriter实现类中输出日志导致死循环问题 4.7.0 30dea0c - 规范化结果
OnResponseStatusCodes方法在Response已完成写入时设置出现异常问题 4.7.2 #I5YBHL -
L.SetCulture("zh-CN");在Response已完成写入时设置出现异常问题 4.7.2 #I5YBHL - 动态
WebAPI在类上配置[Route]特性且包含[action]模板导致生成错误接口路径 4.7.2 #I5YEZQ - 启用二级虚拟目录
AppSettings:VirtualPath导致swagger的miniprofile加载失败 4.7.3 #I5Z8RM -
LoggingMonitor监听带有[FromServices]的方法参数或接口类型参数出错 4.7.7 3037b04 -
HttpRequest通过.ReadBodyContentAsync()读取不到Body问题 4.7.9 #I60IYU
- 生成
- 其他更改
- 文档
-
IIS回收问题解决方案文档 - 远程请求获取
Cookies文档 -
LoggingMonitor写入数据库文档 - JSON 序列化
DateOnly和TimeOnly类型处理文档 -
HttpContext读取Body内容文档 -
PM2配置文件json部署文档 - 日志记录文档、定时任务文档、远程请求文档、脚手架文档
-
- 特别贡献
v4.6.9(已发布)
v4.6.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5XKW4 2022.10.25v4.6.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5X2Q0 2022.10.22v4.6.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5WQPP 2022.10.20v4.6.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5WOIV 2022.10.20v4.6.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5VPD1 2022.10.14v4.6.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5VIAQ 2022.10.13v4.6.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5V99T 2022.10.12v4.6.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5V6UE 2022.10.12v4.6.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UYQW 2022.10.11v4.6.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UQZ7 2022.10.10
- 新特性
-
LoggingMonitor支持FileResult类型监听 4.6.0 bf9c0b1 -
LogMessage结构UseUtcTimestamp字段,解释日志记录时间格式是UTC还是LOCAL时间 4.6.1 aab0371 - 事件总线模块重试失败后支持回调 4.6.1 #I5UVMV
-
LoggingMonitor支持序列化忽略指定属性名或属性类型 4.6.1 81c6343 -
long序列化丢精度的JsonConvert内置转换器,.AddLongTypeConverters()4.6.5 #I5VJHC aded58d -
app.EnableBuffering()扩展,解决Request.Body不能重复读问题 4.6.5 aded58d - 支持特别接口使用特定的序列化规则 4.6.6 797b0bf
-
LoggingMonitor自动解析JWT时间戳为时间格式 4.6.8 9e31b0b
-
- 突破性变化
- 适配
.NET 6.0.10和.NET 7 RC24.6.2 6bb2fad - 内置
Microsoft.AspNetCore.Mvc.NewtonsoftJson扩展,原因是太多人使用了 4.6.5 aded58d -
4.6.0 ec4838c"some log".SetCategory(name)扩展方法 -
4.6.5 aded58dDateOnlyJsonConverter和DateOnlyOffsetJsonConverter处理 - 事件总线触发处理程序的逻辑,由过去的
foreach改为Parallel.ForEach,吞吐量提升近 4 倍 4.6.4 7384c9c -
名称为.AddDateFormatString().AddDateTimeTypeConverters()4.6.5 aded58d - 重构日志模块设置上下文数据功能 4.6.0 1c198ee
- 适配
查看变化
由于过去版本设置日志上下文有多线程异常和堆内存溢出风险,所以重新设计了日志上下文的写法。
由:
_logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10))
.LogInformation("我是一个日志 {id}", 20);
改为:
using (var scope = _logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10)))
{
_logger.LogInformation("我是一个日志 {id}", 20);
}
// 也可以简写
using var scope = _logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10));
_logger.LogInformation("我是一个日志 {id}", 20);
-
-
远程请求4.6.4 7384c9c.SetTimeout和[Timeout]配置方法,采用全局统一配置
-
查看变化
默认情况下,HttpClient 请求超时时间为 100秒,可根据实际情况进行设置:
// 配置默认 HttpClient
options.AddHttpClient(string.Empty, c =>
{
c.Timeout = TimeSpan.FromMinutes(2);
});
// 配置特定客户端
options.AddHttpClient("github", c =>
{
c.Timeout = TimeSpan.FromMinutes(2);
});
- 问题修复
-
4.5.9+版本新增的IncludeScopes配置导致日志上下文失效 4.6.0 4a76841 - 多个
sql共用DbParameters出现冲突问题 4.6.0 #I5UO2H - 高频率写入日志导致堆内存溢出的异常问题 4.6.0 #I5UJRS
- 框架内部所有使用
.CreateLogger创建的日志对象无法应用上下文问题 4.6.0 ec4838c - 远程请求不能在
Worker Serivce中进行构造函数注入,原因是注册为Scope范围作用域 4.6.3 974f835 - 个别服务器的
SQL Server不支持TLS 1.2协议问题 4.6.3 974f835 -
.ToDictionary()扩展不支持JObject类型问题 4.6.5 #I5VJHC a11bf8d -
LoggingMonitor处理long类型丢精度问题 4.6.5 #I5VJHC aded58d - 动态
WebAPI在class类型上贴[ApiDescriptionSettings(false)]导致接口404问题 4.6.7 #I5WQ18 - 超高频率下发送事件总线消息,但是
GC来不及回收导致内存和CPU爆掉问题 4.6.8 dbc7935 -
JWT模块自动刷新Token达到临界值时导致自动刷新失败,并返回错误的401状态码 4.6.8 #I5WXHZ - 自动生成
vue/react/angular客户端工具库错误处理Token问题 4.6.8 #I5WXHZ - 远程请求没有正确处理
数组和集合类型的url参数 4.6.9 #I5XIQ4 - 自定义
Tenant实体且包含TenantId属性且没有继承EntityBase/Entity基类出现The entity type 'Tenant' requires a primary key to be defined4.6.9 #I4UM3E
-
- 其他更改
- 文档
- 远程请求设置客户端生命周期配置文档和新超时配置文档
-
JSON序列化处理long类型说明文档 -
JSON反序列化DateTimeOffset类型个别格式出错问题解决方案文档 -
Worker Service实现串行操作文档 - 关闭
.NET Core底层日志和远程请求日志文档 - 规范化结果支持特定接口配置独立序列化配置文档
- 日志记录文档、事件总线文档、数据库入门文档、
JSON序列化文档、远程请求文档、安全授权文档、生成前端请求代理文档
v4.5.9(已发布)
v4.5.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5ULWN 2022.10.09v4.5.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5UGNS 2022.10.08v4.5.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U8Q9 2022.10.06v4.5.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U4SG 2022.10.03v4.5.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U413 2022.10.02v4.5.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5U3MK 2022.10.01v4.5.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TXON 2022.09.30v4.5.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TLI6 2022.09.28v4.5.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5TD4X 2022.09.27
- 新特性
-
.AddConsoleFormatter()扩展简化控制台日志模板配置 4.5.0 #I5TCMO - 控制台和文件日志时间默认显示
星期几4.5.1 #I5TKL5 - 控制台和文件日志支持配置
options.DateFormat日期格式化 4.5.1 #I5TKL5 - 控制台日志带颜色输出,比如高亮
日志级别4.5.1 #I5TKL5 - 控制台格式化配置
options.WriteHandler完全自定义配置 4.5.2 7fb3036 - 日志输出
JSON格式化配置 4.5.2 #I5TWC1 #I5OUT1 - 数据库日志写入独立日志模板配置、独立日期格式配置 4.5.2 #I5TWC1
-
LogMessage结构类LogDateTime,ThreadId,State属性 4.5.2 #I5TWC1 -
LoggingMonitor可配置JsonWriterOptions属性 4.5.4 #I5U375 -
Log.ScopeContext和"some log".ScopeContext扩展 4.5.4 8129693 -
HttpContext.SetTokensOfResponseHeaders扩展 4.5.7 3775e65 - 新增远程请求支持
Stream文件格式上传 4.5.8 #I5UF3I - 日志模块可配置是否启用上下文功能
IncludeScopes属性 4.5.9 #I5UJRS -
LoggingMonitor日志筛选WriteFilter配置 4.5.9 6f06f12
-
- 突破性变化
- 😊
Furion框架文档地址为 https://furion.net 4.5.4 2e3d80e -
LoggingMonitor底层逻辑,移除原来的.ScopeContext存储监听信息设计 4.5.2 #I5TWC1 -
主机未启动时构建服务的操作权限,此操作会导致内存激增,受影响方法:4.5.4 #I5U0A4 8129693App.GetOptions系列和App.GetService和Scoped.Create
- 😊
查看变化
近期发现许多开发者在主机还未启动时解析服务,这是非常不正确的行为,会导致启动时内存激增甚至溢出,常见的错误有:
- 在启动的时候通过
Scoped.Create创建作用域 - 在启动的时候通过
App.GetOptions获取选项对象 - 在启动的时候通过
App.GetService<T>解析服务
正确的做法是,启动的时候禁止使用 Scoped.Create 和 App.GetService<T>。
如需启动时获取配置应该通过:App.GetConfig<TOptions>("配置节点", true) 替代 App.GetOptions<TOptions>()。
- 问题修复
- 字符串日志扩展带泛型方法不能正确显示
CategoryName日志类别 4.5.0 #I5TBKL - 控制台日志设置了
.ScopeContext无效问题 4.5.2 7fb3036 -
LoggingMonitor同时配置了局部和全局日志监听触发两次问题 4.5.2 a1a97e8 -
v4.4.8+版本更新导致远程请求在个别情况下出现并发问题 4.5.2 #I5TWL3 -
LoggingMonitor配置了ReturnValueThreshold之后Json被截断引发有效性检测异常 4.5.4 #I5U375 -
LoggingMonitor不支持DataTable,DataSet,Tuple等类型问题 4.5.5 #I5U3VO - 自
v4.5.2+版本升级后出现启动时使用App.GetOptons<TOptions>异常问题 4.5.6 #I5U4OC f9a6587 -
app.UseInject(action)导致死循环 4.5.7 !608 -
LoggingMonitor报空引用异常问题 4.5.8 #I5UGCA !610 - 并发情况下设置日志上下文出现偶然性空引用问题 4.5.9 #I5UJRS
- 字符串日志扩展带泛型方法不能正确显示
- 其他更改
- 文档
- 选项监听出现触发多次的解决方案 #I5T9PR
- 日志记录文档、动态 WebAPI 文档、选项文档、
HttpContext文档、远程请求文档
- 本期亮点
-
- 支持日志配置
JSON格式化输出
- 支持日志配置
查看变化
// 控制台
services.AddConsoleFormatter(options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
// 文件
services.AddFileLogging("mytemplate.log", options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
// 数据库
services.AddDatabaseLogging<DatabaseLoggingWriter>(options =>
{
options.MessageFormat = LoggerFormatter.Json;
});
-
- 支持
LoggingMonitor输出JSON格式
- 支持
查看变化
- 全局/局部启用
Json输出配置
// 全局
services.AddMonitorLogging(options =>
{
options.JsonBehavior = Furion.Logging.JsonBehavior.OnlyJson;
});
// 局部
[LoggingMonitor(JsonBehavior = Furion.Logging.JsonBehavior.OnlyJson)]
只有设置为 JsonBehavior.OnlyJson 时才不会输出美观的日志。
- 写入存储介质
using Furion.Logging;
namespace Your.Core;
public class DatabaseLoggingWriter : IDatabaseLoggingWriter
{
// 支持构造函数注入任何实例,会自动释放任何服务,比如注入 IRepository,或者 SqlSugarClient
public DatabaseLoggingWriter()
{
}
public void Write(LogMessage logMsg, bool flush)
{
// 如果 JsonBehavior 配置为 OnlyJson 或者 All,那么 Context 就包含 loggingMonitor 的值
// 如果 JsonBehavior 配置为 OnlyJson,那么可直接通过 logMsg.Message 获取结果就是 json 格式
if (logMsg.LogName == "System.Logging.LoggingMonitor")
{
var jsonString = logMsg.Context.Get("loggingMonitor");
}
// 这里写你任何插入数据库的操作,无需 try catch
}
}
Json 输出格式如下:
{
"controllerName": "test-logger",
"controllerTypeName": "TestLoggerServices",
"actionName": "person",
"actionTypeName": "GetPerson",
"areaName": null,
"displayName": "Furion.Application.TestLoggerServices.GetPerson (Furion.Application)",
"localIPv4": "0.0.0.1",
"remoteIPv4": "0.0.0.1",
"httpMethod": "GET",
"requestUrl": "https://localhost:5001/api/test-logger/person/2",
"refererUrl": "https://localhost:5001/api/index.html?urls.primaryName=数据库操作演示",
"environment": "Development",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.53",
"requestHeaderAuthorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjEsIkFjY291bnQiOiJhZG1pbiIsImlhdCI6MTY2NDQ1MDUwNSwibmJmIjoxNjY0NDUwNTA1LCJleHAiOjE2NjQ0NTE3MDUsImlzcyI6ImRvdG5ldGNoaW5hIiwiYXVkIjoicG93ZXJieSBGdXJpb24ifQ.-xocNcDQGoXClceoVU5QAHIkTcOZ7ZXo0hEbzghDfFI",
"timeOperationElapsedMilliseconds": 55,
"authorizationClaims": [
{
"type": "UserId",
"valueType": "integer",
"value": "1"
},
{
"type": "Account",
"valueType": "string",
"value": "admin"
},
{
"type": "iat",
"valueType": "integer",
"value": "1664450505"
},
{
"type": "nbf",
"valueType": "integer",
"value": "1664450505"
},
{
"type": "exp",
"valueType": "integer",
"value": "1664451705"
},
{
"type": "iss",
"valueType": "string",
"value": "dotnetchina"
},
{
"type": "aud",
"valueType": "string",
"value": "powerby Furion"
}
],
"parameters": [
{
"name": "id",
"type": "System.Int32",
"value": 2
}
],
"returnInformation": {
"type": "Furion.UnifyResult.RESTfulResult`1[[System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]",
"actType": "Furion.Application.Persons.PersonDto",
"value": {
"StatusCode": 200,
"Data": {
"Id": 2,
"Name": null,
"Age": 0,
"Address": null,
"PhoneNumber": null,
"QQ": null,
"CreatedTime": "0001-01-01T00:00:00+00:00",
"Childrens": null,
"Posts": null
},
"Succeeded": true,
"Errors": null,
"Extras": null,
"Timestamp": 1664450517341
}
},
"exception": {
"type": "System.DivideByZeroException",
"message": "Attempted to divide by zero.",
"stackTrace": " at Furion.Application.TestLoggerServices.测试日志监听8(Int32 id) in D:\\Workplaces\\OpenSources\\Furion\\samples\\Furion.Application\\TestLoggerServices.cs:line 78\r\n at lambda_method103(Closure , Object , Object[] )\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"
},
"validation": {
"errorCode": null,
"originErrorCode": null,
"message": "出错了啊。。。。"
}
}
-
- 支持远程请求上传文件
Stream流
- 支持远程请求上传文件
查看变化
- 单文件上传
- 字符串方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await "https://localhost:44316/api/test-module/upload-file"
.SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", fileStream, "image.png")).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 代理方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await _http.TestSingleFileProxyAsync(HttpFile.Create("file", fileStream, "image.png"));
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 多文件上传
- 字符串方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await "https://localhost:44316/api/test-module/upload-muliti-file"
.SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (fileStream, "image1.png"), (fileStream, "image2.png"))).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 代理方式
var fileStream = new FileStream("image.png", FileMode.Open);
var result = await _http.TestMultiFileProxyAsync(HttpFile.CreateMultiple("files", (fileStream, "image1.png"), (fileStream, "image2.png")));
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
- 还支持
Bytes和Stream混合
var fileStream = new FileStream("image.png", FileMode.Open);
var bytes = File.ReadAllBytes("image.png");
var httpFile = new HttpFile
{
Name = name,
Bytes = bytes,
FileStream = fileStream,
FileName = fileName
};
var result = await "https://localhost:44316/api/test-module/upload-file"
.SetContentType("multipart/form-data")
.SetFiles(httpFile).PostAsync();
var fileName = await result.Content.ReadAsStringAsync();
await fileStream.DisposeAsync();
-
LoggingMonitor全局过滤
查看变化
services.AddMonitorLogging(options =>
{
options.WriteFilter = (context) =>
{
// 获取控制器/操作描述器
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
// 你的逻辑....,不需要拦截返回 false,否则 true
return true;
};
});
v4.4.9(已发布)
v4.4.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SP37 2022.09.23v4.4.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SKUE 2022.09.22v4.4.7版本细节:https://gitee.com/dotnetchina/Furion/issues/I5SEFE 2022.09.21v4.4.6版本细节:https://gitee.com/dotnetchina/Furion/issues/I5RSFD 2022.09.19v4.4.5版本细节:https://gitee.com/dotnetchina/Furion/issues/I5RHQX 2022.09.16v4.4.4版本细节:https://gitee.com/dotnetchina/Furion/issues/I5R5TI 2022.09.15v4.4.3版本细节:https://gitee.com/dotnetchina/Furion/issues/I5QVH3 2022.09.13v4.4.2版本细节:https://gitee.com/dotnetchina/Furion/issues/I5QDHX 2022.09.08v4.4.1版本细节:https://gitee.com/dotnetchina/Furion/issues/I5Q3SX 2022.09.07v4.4.0版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PQHR 2022.09.05
- 新特性
- 友好异常可控制是否输出错误日志配置
LogError: true4.4.0 #I5PKJH -
DateOnlyJsonConverter和DateOnlyOffsetJsonConverter序列化转换器 !565 - 事件总线
LogEnabled配置,可控制是否输出服务日志 #I5QLY5 - 可实现任何多套规范化结果功能,支持特定控制器,特定方法 #I5QZ37
-
ILoggerFactory日志工厂动态批量添加文件日志扩展 #I5R9PO -
App.GetCommandLineConfiguration(args)解析命令行参数静态方法 803542c -
Sql代理支持返回受影响行数 #I5REJ9 - 任意自定义日志文件名支持滚动日志删除功能 #I5RFBQ
-
.pcd图片类型MIME为image/x-photo-cd支持 5fafc84 - 默认日志输出当前线程
Environment.CurrentManagedThreadIdb8fe2cd -
app.UseInject(Action<UseInjectOptions>)重载方法,简化配置 4.4.8 0b645fe
- 友好异常可控制是否输出错误日志配置
- 突破性变化
查看变化
public interface IHttp : IHttpDispatchProxy
{
[Post("https://furion.net/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(HttpFile file);
// 支持多个文件
[Post("https://furion.net/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(HttpFile[] files);
// 支持多个文件
[Post("https://furion.net/upload", ContentType = "multipart/form-data")]
Task<HttpResponseMessage> PostXXXAsync(IList<HttpFile> files);
}
// bytes 可以通过 File.ReadAllBytes(文件路径) 获取
var res = await "https://furion.net/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", bytes, "image.png")).PostAsync();
// 支持多个文件
var res = await "https://furion.net/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (bytes, "image1.png"), (bytes, "image2.png"))).PostAsync();
-
- 所有的
AddInject和UseInject参数设计 #I5QCF0
- 所有的
查看变化
public void ConfigureServices(IServiceCollection services)
{
services.AddInject(options =>
{
options.ConfigureSwaggerGen(gen =>
{
// ...
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseInject(configure: options =>
{
options.ConfigureSwagger(swg =>
{
// ...
});
options.ConfigureSwaggerUI(ui =>
{
// ...
});
});
}
-
- 远程请求所有
xxxAsStreamAsync返回值 #I5QVEB
- 远程请求所有
查看变化
由:
var stream = await "https://furion.net/".GetAsStreamAsync();
改为:
var (stream, encoding) = await "https://furion.net/".GetAsStreamAsync();
-
-
.Inject()支持配置更多参数,开放底层更多权限 4.4.9 1182283
-
查看变化
.Inject((builder, options) => {
options.ConfigureAppConfiguration((context, config) =>
{
});
options.ConfigureServices((context, services) =>
{
});
});
- 问题修复
- 远程请求代理模式非泛型参数导致数组溢出问题 #I5Q3SN
-
LoggingMonitor客户端IP记录错误 #I5QCU1 !562 - 远程请求响应报文中包含
charset=gbk进行序列化后乱码问题 #I5QVEB - 文件日志断电时丢失日志问题 db7d51b
- 动态
WebAPI或控制台贴了[ApiDescriptionSettings(Tag = "")]标签之后导致注释丢失 #I5REVF #I5RE4J - 启用数据库日志但是没有配置配置文件出现空异常问题 33817be
- 控制台日志过滤无法过滤默认主机日志问题 33817be
- 脚手架错误的日志配置问题 33817be
- 高频压测情况下写日志并设置日志上下文导致并发更新出现
System.AggregateException异常问题 #I5RFBQ - 日志文件名因
Windows和Linux路径分隔符不一致导致日志文件创建失败问题,Linux只支持/不支持\#I5RFBQ -
Oops.Oh/Bah设置.WithData之后无效问题 !580 - 基于
Redis重写事件存储器序列化IEventSource实例异常问题 4.4.7 3e45020 - 使用
Log静态类超高频率下写日志导致CPU激增问题 4.4.7 #I5SDK5 - 远程请求超高频率下发送请求导致
CPU激增问题和异常问题 4.4.8 #I5SJJR - 集成第三方配置中心时获取的不是最新数据问题 4.4.9 2cdef6b
- 其他更改
- 文档
-
.NET6升级.NET7文档 -
ASP.NET 7集成文档 - 集成第三方配置中心文档 4.4.9
- 第三方事件总线和
Furion集成文档 4.4.9 - 事件总线集成
Kafka文档 #I5P5UG - 友好异常文档、日志记录文档、远程请求文档、依赖注入文档、即时通讯文档、事件总线文档、Worker Service 文档、单元测试文档、入门指南文档、数据库新增文档
-
v4.3.9(已发布)
v4.3.9版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PIWD 2022.09.03v4.3.8版本细节:https://gitee.com/dotnetchina/Furion/issues/I5PCXK 2022.09.02
- 新特性
-
AppSettings配置的ExcludeAssemblies属性,支持忽略指定程序集扫描 7b7747f -
Oops.Oh和Oops.Bah支持设置额外数据.WithData(data)#I5O38E - 定时任务
Crontab.GetSleepMilliseconds(baseTime)获取下一个发生时间的时间差 d024fae - 友好异常默认打印异常日志,避免生产环境漏掉重要异常信息 6e3a5bd
- 日志静态类
Log.CreateLoggerFactory()静态方法 75c672a - 多语言
SharedResource模式,避免硬编程 18e80c7 - 事件总线
MessageCenter静态类,解决从Fur v1.x版本升级问题 a29fc7c - 组件化
IWebComponent模式,支持.NET5+08a44c3 - 远程请求设置自己的
HttpClient功能 #I5PBR3 !545 -
LoggingMonitor支持添加更多自定义配置 #I5PEPA -
LoggingMonitor可配置WithReturnValue和ReturnValueThreshold#I5PFJ1 #I5PFOW -
LoggingMonitor可配置MethodsSettings更多信息 #I5PFJ1 #I5PFOW
-
查看变化
Serve.Run(RunOptions.Default
.AddWebComponent<XXXWebComponent>());
public class XXXWebComponent : IWebComponent
{
public void Load(WebApplicationBuilder builder, ComponentContext componentContext)
{
// ....
}
}
- 突破性变化
查看变化
[Interceptor(InterceptorTypes.Request)]
static void OnRequest(HttpClient client, HttpRequestMessage req)
{
}
[Interceptor(InterceptorTypes.Response)]
static void OnResponsing(HttpClien client, HttpResponseMessage res)
{
}
[Interceptor(InterceptorTypes.Exception)]
static void OnException(HttpClient client, HttpResponseMessage res, string errors)
{
}
- 问题修复
- 其他更改
- 文档
-
RabbitMQ事件总线文档 -
AppSettings配置文档、事件总线文档、多数据库配置文档、日志文档、定时任务文档、MessageCenter文档、远程请求文档、组件化文档、入门指南、多语言文档。
-
v4.2.13(已发布)
- 新特性
- 事件总线工厂,支持运行时动态添加订阅程序和移除订阅程序 #I5NNQX
- 事件总线
[EventSubscribe]事件Id支持正则表达式匹配 #I5NNQX - 事件总线
[EventSubscribe]支持局部失败重试配置 #I5NNQX -
Log全局静态类,方便随时随地记录日志 ba9b1f1 - 事件总线
options.AddSubscriber(Type)重载 42446078 -
ValidationMetadata类型FirstErrorProperty和FirstErrorMessage属性 #I5MFJT -
Serve.Run()模式WithArgs(args)方法 #I5MOJB -
[UnitOfWork]分布式事务TransactionScope支持 #I5MRTY - 16 位
MD5加密支持 #I5N8RC
- 突破性变化
-
Scoped.Create(async (f,s) => {})异步创建作用域方法名称为CreateAsync,避免一些情况下无法区分,同步方法不变 #I5N9XY
-
查看变化
由:
// Scoped.CreateUow 一样
await Scoped.Create(async (f, s) => {});
改为:
// Scoped.CreateUowAsync 一样
await Scoped.CreateAsync(async (f, s) => {});
-
-
.NET 6.0.8和.NET 7 Preview 7842d4f7
-
-
-
[LoggingMonitor]命名空间为System,因为使用频率越来越高 b879861
-
-
- 在非
Web环境中不正确使用字符串扩展方法检测机制 6389cbd
- 在非
-
- 所有
.Default静态属性为.Default()方法 6389cbd
- 所有
-
- 工作单元
IUnitOfWork所有方法参数类型,由ActionExecutingContext和ActionExecutedContext改为FilterContext#I5MHX5
- 工作单元
查看变化
public interface IUnitOfWork
{
void BeginTransaction(FilterContext context, UnitOfWorkAttribute unitOfWork);
void CommitTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork);
void RollbackTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork);
void OnCompleted(FilterContext context, FilterContext resultContext);
}
- 问题修复
- 日志上下文数据多次写入被清空问题以及数据库日志出现异常后停止写入 #I5LIWF
- 个别情况下跨域默认配置的响应缓存导致嵌入式资源异常问题 7a57efe
- 远程请求传入不合法的请求报文头数据触发校验失败问题 #I5LPFE
- 多线程中使用静态日志写数据库日志导致连接池耗光问题 8d5cdd6
-
EFCore 6.0之后IModelCacheKeyFactory接口方法改变导致分表分库异常问题 #I5MCZ6 EFCore#25154 EFCore!3305 -
ValidationMetadata对象Message字符串类型出现\"\"问题 #I5MFJT -
[IfException]覆盖Oops.Oh/Bah错误消息问题 4bbd854 - 数据库日志写入循环写入和频繁创建数据库连接池问题 9ce214c
-
Razor Pages不支持全局异常拦截问题 #I5MHX5 -
Razor Pages不支持全局数据验证问题 #I5MHX5 -
Razor Pages不支持工作单元[UnitOfWork]问题 #I5MHX5 -
Razor Pages不支持EFCore自动SaveChanges问题 #I5MHX5 -
Blazor Server因v4.2.2版本更新导致的问题 #I5MNFN -
[IfException]不支持多语言配置问题 #I5MPN7 - 通过
services.AddMvcFilter<LoggingMonitorAttribute>()方式注册无效问题 8d1477d - 事件总线默认
Channel管道初始化时机过晚问题,解决部分第三方依赖使用问题 #I5MM3O - 主机停止时写入日志异常问题 #I5N7S2
- 数据库上下文手动释放导致
AutoSaveChange特性出现释放异常问题 #I5NFWC -
[LoggingMonitor]循环引用序列化问题 #I5NRT9 - 远程请求传入
nullBody 参数抛出空异常问题 #I5NTUE - 事件总线默认开启模糊匹配(正则表达式)导致不必要的订阅 #I5NVOP
- 其他更改
- 文档
- 全局日志静态类
Log文档 ba9b1f1 -
NuGet本地测试包文档 - 日志文档、静态类文档、数据校验文档、Worker Service 文档、工作单元文档、依赖注入文档
- 全局日志静态类
v4.1.14(已发布,全新单元测试)
单元测试和集成测试是保证一个系统能够持续维护和稳定运行的必备技能,但是目前现有的单元测试组件无法直接集成 Furion 的功能,最常用的就是如何在单元测试中读取配置,以及如何进行依赖注入。
在过去,Furion 只能不断的去调整,以至于适配第三方单元测试写法,搞得不伦不类!
所以,这一次不再妥协,Furion 推出自己的单元测试工具,可以让现有的单元测试如 Xunit 100% 支持 Furion 所有功能,全部保证一致的写法。
- 新特性
-
Furion.Xunit扩展包,正式实现Xunit单元测试完整支持Furion063a034e -
services.AddMonitorLogging()日志监视器服务,支持非常灵活的日志操作 81df742 -
Serve.Run(silence: true)等一系列强大的静默启动功能 #I5JBSQ #I5J98T 7cced4 -
SpecificationDocumentBuilder.GetOpenApiGroups()方法获取底层的规范化接口分组信息 4ff03c5 -
logger.ScopeContext()配置日志上下文功能 #I5JC0D - 跨域配置
CorsAccessorSettings.SignalRSupport配置选项,支持配置SignalR跨域 #I5JREM - 事件总线
UseUtcTimestamp选项配置,可选择使用DateTime.UtcNow还是DateTime.Now,默认是DateTime.Now#I5JSEU - 规范化文档
[OperationId]配置,解决自定义Swagger UI不能正确显示路由问题 #I5K1IB - 远程请求
IHttpDispatchProxy方式全局拦截支持多态(继承) #I5K8FS
-
- 突破性变化
-
Furion.Xunit扩展包,正式实现Xunit单元测试完整支持Furion063a034e -
查看最新实现文档Furion.Extras.DatabaseAccessor.SqlSugar扩展插件中的[SqlSugarUnitOfWork]工作单元特性,将使用通用工作单元替换 -
200848eInject.Create()方法,再也不需要了,框架提供了无敌强大的Serve.Run()静默启动方式 -
Serve.Run的ConfigureConfiguration方法参数,由configuration => {}改为(environment, configuration) => {}83c97bb
-
查看变化
// 由
Serve.Run(RunOptions.Default.ConfigureConfiguration(configuration => {
}));
// 改为:
Serve.Run(RunOptions.Default.ConfigureConfiguration((environment, configuration) => {
}));
- 问题修复
-
[LoggingMonitor]异常消息日志级别为Information错误问题 ab46cdf - 新版本日志组件频繁提示文件占用问题,将文件独占锁改为共享锁 #I5J3S6
- 配置数据库日志读写器为
EFCore时控制台出现无限打印问题 #I5J474 -
[LoggingMonitor]针对byte[]类型参数输出过大问题 5380f35 - 友好异常和规范化结果丢失了原始
ErrorCode问题 #I5IX2R - 新版本日志组件自定义数据库读写器注入
IRepository仓储导致死循环问题 #I5IX2R -
Mvc默认手动验证和Furion全局验证冲突问题 2a06c39 -
Serve.Run()模式不支持SuperSocket第三方包问题,原生是支持的。186ca0a -
SignalR跨域错误问题 #I5JREM -
[LoggingMonitor]将Oops.Oh和Oops.Bah记录到了错误日志中,默认应该是Information且提供可配置 #I5JZ1H - 自定义
Swagger UI之后个别UI要求必须配置operationId,否则出现guid序号 #I5K1IB - 主动抛出
NotFoundResult和NotFoundObjectResult无效问题 #I5KALZ -
[LoggingMonitor]解析方法参数但前端未传入时出现错误问题 #I5KC5P -
[LoggingMonitor]无法序列化IQueryable返回值问题 #I5KJD1 -
[LoggingMonitor]不能记录全局验证错误问题 b44087d -
[LoggingMonitor]存在注册顺序差异问题 b44087d
-
- 其他更改
- 底层的规范化文档
SpecificationDocumentBuilder部分方法,提供更加便捷的第三方Swagger UI集成 10f0f01
- 底层的规范化文档
- 文档
- 单元测试文档、入门指南文档、Worker Services 文档
- 本期亮点
Serve.Run()彻彻底底支持全平台,提供非常强大的静默模式
启用静默模式可以实现无阻塞方式执行程序,而且还能体验完整的 Furion 功能。
查看变化
有了 Serve.Run() 静默模式后,Furion 彻彻底底支持全平台,不管你是 控制台、Web、桌面、移动、单元测试,集成测试,基准测试等等应用程序。
Serve.Run(silence: true);
// 不会阻塞执行哦,而且从这里开始可以使用 Furion 任何功能,比如 App.Configuration....
Console.WriteLine("Hello, World!");
Console.ReadKey();
还有更多静默模式。
// RunOptions 方式
Serve.Run(RunOptions.DefaultSilence);
// LegacyRunOptions 方式
Serve.Run(LegacyRunOptions.DefaultSilence);
// GenericRunOptions 方式
Serve.Run(GenericRunOptions.DefaultSilence);
- 强大的
Furion.Xunit单元测试、集成测试
查看变化
单元测试中初始化 Furion
using Furion.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
// 配置启动类类型,第一个参数是 TestProgram 类完整限定名,第二个参数是当前项目程序集名称
[assembly: TestFramework("TestProject1.TestProgram", "TestProject1")]
namespace TestProject1;
/// <summary>
/// 单元测试启动类
/// </summary>
public class TestProgram : TestStartup
{
public TestProgram(IMessageSink messageSink) : base(messageSink)
{
// 初始化 Furion
Serve.Run(silence: true);
}
}
测试类支持完整依赖注入
using TestProject1.Services;
using Xunit;
namespace TestProject1;
public class UnitTest1
{
private readonly ICalcService _calcService;
public UnitTest1(ICalcService calcService)
{
_calcService = calcService;
}
[Fact]
public void 测试两个数的和()
{
Assert.Equal(3, _calcService.Plus(1, 2));
}
}

- 开放底层规范化文档分组接口,使得集成第三方
Swagger UI更加容易,如集成IGeekFan.AspNetCore.Knife4jUI扩展:
查看变化
只需要在 YourPoject.Web.Core 层安装 IGeekFan.AspNetCore.Knife4jUI 即可。
3.1.1 Knife4jUI 独立版本配置
var routePrefix = "api"; // 定义 swagger 路由地址,如果是根目录,设置 string.Empty 即可
app.UseKnife4UI(options =>
{
options.RoutePrefix = routePrefix; // 配置 Knife4UI 路由地址
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
{
options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
}
});
app.UseInject(routePrefix); // 配置 Furion 路由地址
3.1.2 Knife4jUI 和 Swagger 共存版本配置
app.UseKnife4UI(options =>
{
options.RoutePrefix = "newapi"; // 配置 Knife4UI 路由地址,现在是 /newapi
foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
{
options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
}
});
app.UseInject(); // Furion 默认 api 地址为 /api

如需实现登录之后自动将 token 添加到头部可在登录接口 AfterScript 执行以下代码:
ke.global.setAllHeader(
"Authorization",
"Bearer " + ke.response.headers["access-token"],
);

- 提供强大的日志上下文功能
// 写法一
_logger.ScopeContext(ctx => ctx.Set("Name", "Furion").Set("UserId", 10))
.LogInformation("我是一个日志 {id}", 20);
// 写法二
_logger.ScopeContext(new Dictionary<object, object> {
{ "Name", "Furion" },
{ "UserId", 10 }
}).LogInformation("我是一个日志 {id}", 20);
// 写法三
_logger.ScopeContext(new LogContext {
// ....
}).LogInformation("我是一个日志 {id}", 20)
v4.0.0(重新起航)💖
2020 年 09 月 01 日,一个叫 Fur 的开源项目在 Gitee 的襁褓中悄然诞生,她的出生仿佛带着某种使命,没有包袱,无限可能。
她缓缓的张开双眼,干净雪亮的眼睛似乎对这个世界充满了好奇,任何事物在她眼前晃过都像是直击灵魂的思想碰撞,这些在她看来都是非常宝贵的财富。她貌似有用不完的精力,一路汲取知识,升级打怪,不断奔跑,乐此不疲。
记得 2020 年 11 月 11 日的单身节,她迎来了“一岁(v1.0.0)”生日,自那以后,IT 这个大银幕上频繁出现她的身影,越来越多 .NET5 开发者转粉,像是告诉这个世界,她就是 IT 界大明星。
每一个明星都有一个好听的艺名,她当然也不例外,2020 年 11 月 20 日,经纪人百小僧为她起名为 Furion。
2021 年 11 月 09 日起,她进入了每个孩子都经历过的叛逆期,年少轻狂喜新厌旧,抛弃了曾经支持她的 .NET5 粉丝们,投入到新的 .NET6 拥趸者怀抱中,自此过上了奢靡富足的生活。
但她过的不开心,时常在夜里想起 .NET5 的粉丝们,内心非常自责,但在双重工作压力下她毅然选择了忽视他们的诉求,仿佛他们就是累赘。
时间真的是好东西,曾经认为是对的,经过岁月的蹉跎历磨,渐渐的明白:不忘初心,方能始终。
这一次,不落下一人(.NET5,.NET6,...,.NET N),携手共进,重新起航,感恩遇见,感恩信任。
- 新特性
v4.0.0支持.NET5,.NET6,...,.NET N,所有的Furion项目都能够升级到该版本,重新起航,实现大统。