两千星 .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 ...
随机推荐
- 【mq读书笔记】mq读写分离机制
mq根据brokerName查找Broker地址的过程 mq根据MessageQueue查找Broker地址的唯一依据是brokerName,同一组Broker(M-S)他们的bokerName相同但 ...
- TensorFlow安装方法:附带坑解决办法
>>添加Anaconda 仓库的镜像 Anaconda 安装包可以到 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 下载. ...
- 【2020.12.01提高组模拟】卡特兰数(catalan)
题目 题目描述 今天,接触信息学不久的小\(A\)刚刚学习了卡特兰数. 卡特兰数的一个经典定义是,将\(n\)个数依次入栈,合法的出栈序列个数. 小\(A\)觉得这样的情况太平凡了.于是,他给出了\( ...
- Spring Cloud Alibaba 初体验(二) Nacos 服务注册与发现 + 集成 Spring Cloud Gateway
一.服务注册 添加依赖: <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>s ...
- Spring Boot + RabbitMQ 使用示例
基础知识 虚拟主机 (Virtual Host): 每个 virtual host 拥有自己的 exchanges, queues 等 (类似 MySQL 中的库) 交换器 (Exchange): 生 ...
- Cys_Control(二) MButton
一.添加自定义Button 二.Xaml文件自动关联 Custom Control 取名与资源文件相同加.cs文件将自动关联 Themes文件下Generic.xaml引入该控件,用于对外公布样式 & ...
- MySQL慢查询日志(SLOW LOG)
慢查询日志可以帮助DBA或开发人员定位可能存在问题的SQL语句,从而进行优化. 如何开启 默认情况下,MySQL是不开启慢查询日志的.可以通过以下命令查看是否开启: mysql> SHOW VA ...
- 第14.17节 爬虫实战3: request+BeautifulSoup实现自动获取本机上网公网地址
一. 引言 一般情况下,没有特殊要求的客户,宽带服务提供商提供的上网服务,给客户家庭宽带分配的地址都是一个宽带服务提供商的内部服务地址,真正对外访问时通过NAT进行映射到一个公网地址,如果我们想确认自 ...
- PyQt(Python+Qt)学习随笔:QTreeView树形视图的allColumnsShowFocus属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTreeView树形视图的allColumnsShowFocus属性用于控制是否使视图中的所有列显 ...
- Day7 【Scrum 冲刺博客】
每日会议总结 昨天已完成的工作 方晓莹(PIPIYIng) 对接车位管理接口 处理对接接口遇到的bug和错误 方子茵(Laa-L) 暂无 黄芯悦(Sheaxx) 完成住户车位查询页面 完成住户物业报修 ...