两千星 .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 ...
随机推荐
- 专业五线谱作曲打谱软件Overture的常用快捷键功能大全
快捷命令在我们使用软件时起到的帮助是不言而喻的,它用一个或几个简单的字母来代替常用的命令,使我们不用去记忆众多的长长的命令,也不必为了执行一个命令,在菜单和工具栏上寻寻觅觅.当然,随着Overture ...
- 日期选择组件(DatePicker)的实现
一.效果图 日期选择组件大概长这样: 从效果图可以看出,日期选择组件由两部分组成:日历表格和顶部操作栏. 二.日历表格 日期选择组件的核心主体是日历表格: 可以将日历表格表示成一个7️*的二维数组,数 ...
- HTML的基本术语
一.HTML含义1.根据W3C定义,HTML全称Hyper Text Markup Language: 超文本标记语言,用于定义文档的内容结构,该语言书写的代码通常会被浏览器解析执行.二.css含义1 ...
- VisualStudio C++使用汇编函数
Visual Studio编写C++代码使用汇编函数 新建空项目 新建如下源文件 ;test.asm ;测试函数 三个数相加 ;.386 .model flat, c ;public test_ .c ...
- LaTeX中的特殊字符
空白符号代码及注释: 显示效果: 控制符.排版符号.标志符号.引号.连字符.非英文字符和重音符号的代码及注释: 显示效果:
- Java多线程中的wait/notify通信模式
前言 最近在看一些JUC下的源码,更加意识到想要学好Java多线程,基础是关键,比如想要学好ReentranLock源码,就得掌握好AQS源码,而AQS源码中又有很多Java多线程经典的一些应用:再比 ...
- Less从入门到精通——变量与混合
变量(variables) Less中采用" @ "定义变量,使用时直接使用"@命名符". 作为普通变量 // 命名: @color:red; // 调用: d ...
- 02_启动和销毁Service
在Application关闭后,Service仍然会运行. package com.example.servdemo; import android.app.Activity; import andr ...
- 后端程序员必备的 Linux 基础知识
1. 从认识操作系统开始 正式开始 Linux 之前,简单花一点点篇幅科普一下操作系统相关的内容. 1.1. 操作系统简介 我通过以下四点介绍什么是操作系统: 操作系统(Operating Syste ...
- FM解析(因子分解机,2010)
推荐参考:(知乎) https://zhuanlan.zhihu.com/p/37963267 要点理解: 1.fm应用场景,为什么提出了fm(和lr的不同点) ctr预测,特征组合,fm的隐向量分解 ...