两千星 .NET5 框架 Furion 亮点分析(一)

让 .NET 开发更简单,更通用,更流行。
Furion 介绍
Furion 是基于 .NET5 平台下打造的现代化 Web 框架。旨在 让 .NET 开发更简单,更通用,更流行。。
Furion 非常精悍短小,底层只依赖两个第三方库,去除注释文件仅有 73kb 大小。
麻雀虽小五脏俱全,企业级项目开发所需功能它一个也不少。

开源地址
文档地址
目前文档正在逐步完善中。
项目案例
- 考试君:基于 Furion 的在线考试系统
- 园丁:基于 Furion + Blazor 的超简单后台管理系统
- Queer:基于 Furion + Layui 的通用型管理系统
- Pear Admin:PearAdmin 官方和 Furion 官方合作管理系统
- JoyAdmin:基于 Furion + iviewadmin 开发的管理系统
Furion 亮点介绍
1. 极易集成
Furion 设计遵循“无侵入性或侵入性极小”原则,只需要在 Progame.cs 文件夹中添加 Inject() 方法即可完成初始化配置。
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace FurStart
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.Inject() // 只需这一行即可完成配置
.UseStartup<Startup>();
});
}
}
文档传送门:https://monksoul.gitee.io/furion/docs/get-start
2. 丰富脚手架
Furion 提供了 .NET5 所有 Web 类型的脚手架,可以极速搭建企业项目多层架构。
| 模板类型 | 名称 | 版本 | 描述 |
|---|---|---|---|
| Furion.Template.Mvc | Mvc 模板 | ||
| Furion.Template.Api | WebApi 模板 | ||
| Furion.Template.App | Mvc/WebApi 模板 | ||
| Furion.Template.Razor | RazorPages 模板 | ||
| Furion.Template.RazorWithWebApi | RazorPages/WebApi 模板 | ||
| Furion.Template.Blazor | Blazor 模板 | ||
| Furion.Template.BlazorWithWebApi | Blazor/WebApi 模板 |
文档传送门:https://monksoul.gitee.io/furion/docs/template
3. 极少依赖
Furion 为了追求极速入门,极致性能,尽可能的不使用或减少第三方依赖。目前 Furion 仅集成了以下两个依赖:
- MiniProfiler:性能分析和监听必备
- Swashbuckle:
Swagger接口文档
麻雀虽小五脏俱全。Furion 即使只集成了这两个依赖,但是主流的 依赖注入/控制反转,AOP 面向切面编程,事件总线,数据验证,数据库操作 等等一个都不少。

文档传送门:https://monksoul.gitee.io/furion/docs/
4. appsettings.json 分割合并
默认情况下,.NET5 的配置文件需写在 appsettings.json 文件中,如需添加其他配置,需手动添加并在主机启动时加载进来,Furion 提供了非常灵活方便的方式,支持配置文件放在项目其他位置,并自动加载,自动配置并合并。如:system.json
{
"AppInfo": {
"Name": "Furion",
"Version": "1.7.0"
}
}
此时 system.json 会自动加载并自动合并。
文档传送门:https://monksoul.gitee.io/furion/docs/configuration
5. 热重载配置选项
Furion 提供了非常灵活的选项配置功能,支持后期配置,配置更改通知。
using Furion.ConfigurableOptions;
namespace Furion.Application
{
public class AppInfoOptions : IConfigurableOptionsListener<AppInfoOptions>
{
public string Name { get; set; }
public string Version { get; set; }
public string Company { get; set; }
// 选项更改监听
public void OnListener(AppInfoOptions options, IConfiguration configuration)
{
var name = options.Name; // 实时的最新值
var version = options.Version; // 实时的最新值
}
// 选项后期配置
public void PostConfigure(AppInfoOptions options, IConfiguration configuration)
{
}
}
文档传送门:https://monksoul.gitee.io/furion/docs/options
6. 动态API及变体服务
Furion 提供了动态构建 WebApi 的方式,可以大大提高 WebApi 的开发效率,还能实现 WebApi 服务接口化。
using Furion.DynamicApiController;
namespace Furion.Application
{
public class FurAppService : IDynamicApiController
{
public string Get()
{
return $"GET 请求";
}
public string Post()
{
return $"POST 请求";
}
public string Delete()
{
return $"DELETE 请求";
}
public string Put()
{
return $"PUT 请求";
}
public string Patch()
{
return $"PATCH 请求";
}
}
}
文档传送门:https://monksoul.gitee.io/furion/docs/dynamic-api-controller
7. 统一结果规范化处理
Furion 提供了非常灵活的方式去规范化 WebApi 的返回结果,使其采用统一规范的结果返回。
using Furion.DependencyInjection;
using Furion.Utilities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Furion.UnifyResult
{
/// <summary>
/// RESTful 风格返回值
/// </summary>
[SkipScan, UnifyModel(typeof(RESTfulResult<>))]
public class RESTfulResultProvider : IUnifyResultProvider
{
/// <summary>
/// 异常返回值
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public IActionResult OnException(ExceptionContext context)
{
// 解析异常信息
var (ErrorCode, ErrorContent) = UnifyContext.GetExceptionMetadata(context);
return new JsonResult(new RESTfulResult<object>
{
StatusCode = ErrorCode,
Succeeded = false,
Data = null,
Errors = ErrorContent,
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
});
}
/// <summary>
/// 成功返回值
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public IActionResult OnSucceeded(ActionExecutedContext context)
{
object data;
// 处理内容结果
if (context.Result is ContentResult contentResult) data = contentResult.Content;
// 处理对象结果
else if (context.Result is ObjectResult objectResult) data = objectResult.Value;
else if (context.Result is EmptyResult) data = null;
else return null;
return new JsonResult(new RESTfulResult<object>
{
StatusCode = context.Result is EmptyResult ? StatusCodes.Status204NoContent : StatusCodes.Status200OK, // 处理没有返回值情况 204
Succeeded = true,
Data = data,
Errors = null,
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
});
}
/// <summary>
/// 验证失败返回值
/// </summary>
/// <param name="context"></param>
/// <param name="modelStates"></param>
/// <param name="validationResults"></param>
/// <param name="validateFailedMessage"></param>
/// <returns></returns>
public IActionResult OnValidateFailed(ActionExecutingContext context, ModelStateDictionary modelStates, Dictionary<string, IEnumerable<string>> validationResults, string validateFailedMessage)
{
return new JsonResult(new RESTfulResult<object>
{
StatusCode = StatusCodes.Status400BadRequest,
Succeeded = false,
Data = null,
Errors = validationResults,
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
});
}
/// <summary>
/// 处理输出状态码
/// </summary>
/// <param name="context"></param>
/// <param name="statusCode"></param>
/// <returns></returns>
public async Task OnResponseStatusCodes(HttpContext context, int statusCode)
{
switch (statusCode)
{
// 处理 401 状态码
case StatusCodes.Status401Unauthorized:
await context.Response.WriteAsJsonAsync(new RESTfulResult<object>
{
StatusCode = StatusCodes.Status401Unauthorized,
Succeeded = false,
Data = null,
Errors = "401 Unauthorized",
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
}, JsonSerializerUtility.GetDefaultJsonSerializerOptions());
break;
// 处理 403 状态码
case StatusCodes.Status403Forbidden:
await context.Response.WriteAsJsonAsync(new RESTfulResult<object>
{
StatusCode = StatusCodes.Status403Forbidden,
Succeeded = false,
Data = null,
Errors = "403 Forbidden",
Extras = UnifyContext.Take(),
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
}, JsonSerializerUtility.GetDefaultJsonSerializerOptions());
break;
default:
break;
}
}
}
}
文档传送门:https://monksoul.gitee.io/furion/docs/specification-document#67-统一返回值模型
8. 强大的 Swagger 在线文档
Furion 内置了强大的 Swagger 规范化文档,并赋予了更多强大的能力。

文档传送门:https://monksoul.gitee.io/furion/docs/specification-document
9. 非常强大的数据库操作功能

文档传送门:https://monksoul.gitee.io/furion/docs/dbcontext
10. 异常处理最佳实践
Furion 采用独特的异常处理方案,可以大大的将异常和业务逻辑分离。
using Furion.DynamicApiController;
using Furion.FriendlyException;
namespace Furion.Application
{
public class FurAppService : IDynamicApiController
{
[IfException(typeof(ExceptionType), ErrorMessage = "特定异常类型全局拦截")]
[IfException(ErrorMessage = "全局异常拦截")]
[IfException(ErrorCodes.z1000, ErrorMessage = "我覆盖了默认的:{0} 不能小于 {1}")]
[IfException(ErrorCodes.x1001, "格式化参数1", "格式化参数2", ErrorMessage = "我覆盖了默认的:{0} 不能小于 {1}")]
[IfException(ErrorCodes.x1000, "格式化参数1", "格式化参数2")]
[IfException(ErrorCodes.SERVER_ERROR, "格式化参数1", "格式化参数2")]
public int Get(int id)
{
if (id < 3)
{
throw Oops.Oh(ErrorCodes.z1000, id, 3);
}
return id;
}
}
}
文档传送门:https://monksoul.gitee.io/furion/docs/friendly-exception
11. 强大且灵活的 SaaS 多租户实现方式

文档传送门:https://monksoul.gitee.io/furion/docs/saas
12. 极易使用的对象依赖配置
Furion 提供了三种极易配置的接口依赖配置。
using Furion.Core;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
namespace Furion.Application
{
public interface IBusinessService<T>
{
Person Get(int id);
}
public class BusinessService<T> : IBusinessService<T>, ITransient
{
private readonly IRepository<Person> _personRepository;
public BusinessService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
}
public Person Get(int id)
{
return _personRepository.Find(id);
}
}
}
文档传送门:https://monksoul.gitee.io/furion/docs/dependency-injection
13. 强大的视图引擎
Furion 内置了强大的视图引擎功能,完美支持 Razor 语法。
var result = _viewEngine.RunCompile(@"
Hello @Model.Name
@foreach(var item in Model.Items)
{
<p>@item</p>
}
", new TestModel
{
Name = "Furion",
Items = new[] { 3, 1, 2 }
});
文档传送门:https://monksoul.gitee.io/furion/docs/view-engine
结语
由于篇幅有效,这里只是抛砖引玉,但 Furion 的亮点远不止这些,可以查看文档了解并学习。

文档地址:https://monksoul.gitee.io/furion/
最后,喜欢 Furion 可以给个 Star,您的支持 Furion 才能越走越远。
两千星 .NET5 框架 Furion 亮点分析(一)的更多相关文章
- .NET Core Community 第四个千星项目诞生:微服务框架 Surging
本文所有打赏将全数捐赠于 NCC(NCC 的资金目前由 倾竹大人 负责管理),请注明捐赠于 NCC.捐赠情况将由倾竹大人在此处公示. 提及 .NET 微服务,我们脑海中浮现的一系列印象中,总有 Sur ...
- .NETCore 千星项目模块化开发框架 SimplCommerce 详解
SimplCommerce 是 github 上过千星的.netcore 商城示例项目,本文详解他的模块化框架现实思路,其业务(如产品.订单)不作介绍.因作者文笔水平很差,它又很值得学习和推荐,就算不 ...
- 使用Python爬取淘宝两千款套套
各位同学们,好久没写原创技术文章了,最近有些忙,所以进度很慢,给大家道个歉. 警告:本教程仅用作学习交流,请勿用作商业盈利,违者后果自负!如本文有侵犯任何组织集团公司的隐私或利益,请告知联系猪哥删除! ...
- 介绍开源的.net通信框架NetworkComms框架 源码分析
原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 售价249英镑 我曾经花了 ...
- Android Small插件化框架源码分析
Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github ...
- YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)
YII 框架源码分析 百度联盟事业部——黄银锋 目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 ...
- java fork-join框架应用和分析
http://shmilyaw-hotmail-com.iteye.com/blog/1897636 java fork-join框架应用和分析 博客分类: concurrency multithre ...
- 对比Tornado和Twisted两种异步Python框架
做Python的人,一定知道两个性能优秀的异步网络框架:tornado,和twisted. 那么,这两个著名的框架,又有什么异同呢?tornado和twisted,我都用在几个游戏项目中,做过后端,觉 ...
- Spark RPC框架源码分析(一)简述
Spark RPC系列: Spark RPC框架源码分析(一)运行时序 Spark RPC框架源码分析(二)运行时序 Spark RPC框架源码分析(三)运行时序 一. Spark rpc框架概述 S ...
随机推荐
- 编曲技巧:使用FL Studio来制作停顿的效果
停顿效果是一种在音乐创作中非常常用的音效,它能起到缓冲的作用,而且能使这段旋律更具节奏感,在比较激情的歌曲中尤为常见.例如知名歌手王力宏演唱的<火力全开>中就使用了停顿效果,为歌曲加了不少 ...
- 一道百度java面试题的多种解法
下面是我在2018年10月11日二面百度的时候的一个问题: java程序,主进程需要等待多个子进程结束之后再执行后续的代码,有哪些方案可以实现? 这个需求其实我们在工作中经常会用到,比如用户下单一个产 ...
- 16.java设计模式之迭代器模式
基本需求: 展示一个学校的结构,比如一个学校下面有多个学院,学院下面有多个系,对其节点主要是遍历,与组合模式略有不同 传统方案: 学校<-学院<-系 依次继承 这种方式,在一个页面中展示出 ...
- 第一次UML编程作业
博客班级 https://edu.cnblogs.com/campus/fzzcxy/2018SE2/ 作业要求 https://edu.cnblogs.com/campus/fzzcxy/2018S ...
- Docker 跨平台在 netCore 中的从入门到部署
前言 从题目我们可以看的出,今天是五部曲的第三部,你可能会好奇,为啥没有见到前两部呢?这里我简单说下: 1.跨平台第一部曲:MySql 如果你看我的所有开源项目,应该能发现我已经全部迁移到了Mysql ...
- PyQt(Python+Qt)学习随笔:QListView的itemAlignment属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListView的itemAlignment属性用于控制每个数据项的对齐方式,其类型为枚举类Qt. ...
- ATT&CK 实战 - 红日安全 vulnstack (一) 靶机渗透
关于部署:https://www.cnblogs.com/Cl0ud/p/13688649.html PS:好菜,后来发现内网主机还是PING不通VM1,索性三台主机全部配成NAT模式,按照WEB靶机 ...
- ADF 第二篇:使用UI创建ADF
用户可以通过UI来创建ADF,在UI中创建ADF时,用户不需要下载单独的IDE,而仅仅通过 Microsoft Edge 或者 Google Chrome浏览器.用户登录Azure Portal,选择 ...
- 抖音CK备份上号原理
抖音CK备份和上号是点赞跳频繁上号的最好方式,不会的可以访问网站:rz3w.com,下面介绍备份还原的原理:public void run() { MainActivity.a(this.c); ne ...
- 【C/C++】C和C++11之enum枚举的使用细节
作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14101271.html 目录 一.前言 二.C中的枚举(enum) 2.1 C中枚举的大小 2.2 C中枚举的取 ...