什么是OSharp
OSharpNS全稱OSharp Framework with .NetStandard2.0,是一個基於.NetStandard2.0開發的一個.NetCore快速開發框架。這個框架使用最新穩定版的.NetCore SDK(當前是.NET Core 2.2),對 AspNetCore 的配置、依賴注入、日志、緩存、實體框架、Mvc(WebApi)、身份認證、權限授權等模塊進行更高一級的自動化封裝,並規范了一套業務實現的代碼結構與操作流程,使 .Net Core 框架更易於應用到實際項目開發中。
- 開源地址:https://github.com/i66soft/osharp
- 官方示例:https://www.osharp.org
- 文檔中心:https://docs.osharp.org
- VS 插件:https://marketplace.visualstudio.com/items?itemName=LiuliuSoft.osharp
框架工程組織
框架的工程組織結構如下:

各工程簡介
- OSharp【框架核心組件】:框架的核心組件,包含一系列快速開發中經常用到的Utility輔助工具功能,框架各個組件的核心接口定義,部分核心功能的實現
- OSharp.AspNetCore【AspNetCore組件】:AspNetCore組件,提供AspNetCore的服務端功能的封裝
- OSharp.AutoMapper【對象映射組件】:AutoMapper 對象映射組件,封裝基於AutoMapper的對象映射實現
- OSharp.EntityFrameworkCore【EFCore 數據組件】:EFCore數據訪問組件,封裝EntityFrameworkCore數據訪問功能的實現
- OSharp.EntityFrameworkCore.MySql【EFCore MySql 數據組件】:EFCore MySql數據訪問組件,封裝MySql的EntityFrameworkCore數據訪問功能的實現
- OSharp.EntityFrameworkCore.SqlServer【EFCore SqlServer 數據組件】:EFCore SqlServer數據訪問組件,封裝SqlServer的EntityFrameworkCore數據訪問功能的實現
- OSharp.EntityFrameworkCore.Sqlite【EFCore Sqlite 數據組件】:EFCore Sqlite數據訪問組件,封裝Sqlite的EntityFrameworkCore數據訪問功能的實現
- OSharp.EntityFrameworkCore.PostgreSql【EFCore PostgreSql 數據組件】:EFCore PostgreSql數據訪問組件,封裝PostgreSql的EntityFrameworkCore數據訪問功能的實現
- OSharp.EntityFrameworkCore.Oracle【EFCore PostgreSql 數據組件】:EFCore Oracle數據訪問組件,封裝Oracle的EntityFrameworkCore數據訪問功能的實現
- OSharp.Permissions【權限組件】:使用AspNetCore的Identity為基礎實現身份認證的封裝,以Security為基礎實現以角色-功能、用戶-功能的功能權限實現,以角色-數據,用戶-數據的數據權限的封裝
- OSharp.Log4Net【日志組件】:基於Log4Net的日志記錄組件
- OSharp.Redis【緩存組件】:基於Redis的分布式緩存客戶端組件
- OSharp.Hangfire【后台任務組件】:封裝基於Hangfire后台任務的服務端實現
- OSharp.MiniProfiler【MiniProfiler組件】:基於MiniProfiler實現的性能監測組件
- OSharp.Swagger【SwaggerAPI組件】:基於Swagger生成MVC的Action的API測試接口信息
- OSharp.Exceptionless【Exceptionless分布式日志組件】:封裝基於Exceptionless 分布式日志記錄實現
Nuget Packages
OSharp框架特性
1. 模塊化的組件系統設計
OSharp框架設計了一個模塊(Pack)系統,每個Pack以一個實現了模塊基類(OsharpPack)的類作為入口,這個類完成本模塊的服務添加(AddService)和模塊初始化工作(UserPack)。一個Pack是一系列高內聚低耦合的服務組織,對象提供一個功能(如緩存功能,日志功能,數據存儲功能)或完成一組業務處理(如身份認證,權限授權)。
一個Pack入口類的代碼如下:
public class XXXPack : OsharpPack
{
/// <summary>
/// 獲取 模塊級別
/// </summary>
public override PackLevel Level => PackLevel.Core;
/// <summary>
/// 獲取 模塊啟動順序,模塊啟動的順序先按級別啟動,級別內部再按此順序啟動
/// </summary>
public override int Order => 2;
/// <summary>
/// 將模塊服務添加到依賴注入服務容器中
/// </summary>
/// <param name="services">依賴注入服務容器</param>
/// <returns></returns>
public override IServiceCollection AddServices(IServiceCollection services)
{
// TODO: 在這里添加本模塊涉及的各種依賴注入服務
return services;
}
/// <summary>
/// 應用模塊服務
/// </summary>
/// <param name="provider">服務提供者</param>
public override void UsePack(IServiceProvider provider)
{
// TODO: 在這里進行模塊的初始化操作
IsEnabled = true;
}
}
當前框架的模塊組成如下圖:
| 名稱 | 類型 | 級別 |
|---|---|---|
| OSharp核心模塊 | OSharp.Core.Packs.OsharpCorePack | Core |
| 依賴注入模塊 | OSharp.Dependency.DependencyPack | Core |
| Log4Net模塊 | OSharp.Log4Net.Log4NetPack | Core |
| AspNetCore模塊 | OSharp.AspNetCore.AspNetCorePack | Core |
| 事件總線模塊 | OSharp.EventBuses.EventBusPack | Core |
| AutoMapper模塊 | OSharp.AutoMapper.AutoMapperPack | Framework |
| Hangfire后台任務模塊 | OSharp.Hangfire.HangfirePack | Framework |
| Redis模塊 | OSharp.Redis.RedisPack | Framework |
| MySqlEntityFrameworkCore模塊 | OSharp.Entity.MySql.MySqlEntityFrameworkCorePack | Framework |
| SqliteEntityFrameworkCore模塊 | OSharp.Entity.Sqlite.SqliteEntityFrameworkCorePack | Framework |
| SqlServerEntityFrameworkCore模塊 | OSharp.Entity.SqlServer.SqlServerEntityFrameworkCorePack | Framework |
| SqlServer-DefaultDbContext遷移模塊 | OSharp.Site.Web.Startups.SqlServerDefaultDbContextMigrationPack | Framework |
| MVC功能點模塊 | OSharp.AspNetCore.Mvc.MvcFunctionPack | Application |
| 數據實體模塊 | OSharp.Core.EntityInfos.EntityInfoPack | Application |
| 系統信息模塊 | OSharp.Systems.SystemPack | Application |
| 身份認證模塊 | OSharp.Site.Identity.IdentityPack | Application |
| MVC模塊 | OSharp.Site.Web.Startups.AspNetCoreMvcPack | Application |
| SignalR模塊 | OSharp.Site.Web.Startups.SignalRPack | Application |
| 權限安全模塊 | OSharp.Site.Security.SecurityPack | Application |
| 代碼生成模塊 | OSharp.Site.Web.Startups.CodeGeneratorPack | Application |
| SwaggerApi模塊 | OSharp.Swagger.SwaggerPack | Application |
| 審計模塊 | OSharp.Site.Systems.AuditPack | Application |
2. 自動化的依賴注入注冊機制
空接口標注方式
框架定義了ISingletonDependency,IScopeDependency,ITransientDependency 三個空接口,對應着依賴注入的ServiceLifetime.Singleton、ServiceLifetime.Scoped、ServiceLifetime.Transient三種服務生命周期。按需要實現了空接口的服務類,將在系統初始化時被檢索出來進行實現類與其接口的依賴注入服務注冊。
空接口的標注方式,統一使用TryAdd來進行注入
一個示例代碼如下:
public XXXService : IXXXService, ISingletonDependency
{ }
這個示例代碼將在系統初始化時執行如下的注入行為:
// 空接口的標注方式,統一使用TryAdd來進行注入
services.TryAdd(new ServiceDescriptor(typeof(IXXXService),
typeof(XXXService), ServiceLifetime.Singleton));
DependencyAttribute特性標注方式
空接口的標注方式,只能指定服務的注冊生命周期類型,而不能進行更多的配置,因此增加了[Dependency]特性的標注方式。通過[Dependency],可以進行 服務注冊的生命周期類型、是否是TryAdd方式注冊、是否替換已存在的服務、是否注冊自身 等配置,使用起來更加靈活方便。
一個示例代碼如下:
[Dependency(ServiceLifetime.Singleton, ReplaceExisting = true, AddSelf = true)]
public XXXService : IXXXService
{ }
這個示例代碼將在系統初始化時執行如下的注入行為:
// replace
services.Replace(new ServiceDescriptor(typeof(IXXXService),
typeof(XXXService), ServiceLifetime.Singleton));
// add self
services.TryAdd(new ServiceDescriptor(typeof(XXXService),
typeof(XXXService), ServiceLifetime.Singleton));
自動化的注冊機制
系統初始化時,通過反射檢索程序集的方式,檢索出所有服務類型(ServiceType)與服務實現(ImplementationType)及生命周期類型(ServiceLifetime)的相關數據,將依賴注入服務注冊到服務容器ServiceCollection中。
3. UnitOfWork-Repository模式,EFCore上下文動態構建
- 數據模塊使用了UnitOfWork-Repository的模式來設計,設計了一個泛型的實體倉儲接口IRepository<TEntity,TKey>,避免每個實體都需實現一個倉儲的繁瑣操作。設計了IUnitOfWorkManager接口來管理多數據庫連接事務,每個IUnitOfWork,通過IUnitOfWork模式管理DbContext的創建與緩存,使同連接對象的多個上下文共享事務,達到多上下文的事務同步能力。
- 基於MVC的ActionFilter的UnitOfWorkAttribute AOP 事務自動提交,業務中不再需要關心事務的生命周期。
- 系統初始化時,通過反射檢索程序集的方式,檢索出各個實體與上下文的映射關系,向上下文中動態添加實體類來構建上下文類型,以達到上下文類型與業務實體解耦的目的。通過統一基類EntityTypeConfigurationBase<TEntity, TKey>的FluentAPI實體映射,自由配置每個實體與數據庫映射的每一個細節。
4. 基於AspNetCore的Identity的身份認證設計系統
- 使用AspNetCore原生的用戶身份認證框架,身份認證相關操作統一使用UserManager
,RoleMamanger 兩個入口,保持了原生Identity的體系強大性與功能完整性。 - 重新設計了用戶存儲UserStore和角色存儲RoleStore,使用框架內設計的IRepository<TEntity,TKey>數據倉儲接口來實現對數據的倉儲操作,使Identity身份認證系統與框架完美結合,避免了使用官方的Microsoft.AspNetCore.Identity.EntityFrameworkCore造成多個上下文或者被強制使用Identity上下文作為系統數據上下文來實現業務造成的尷尬。
5. 設計了一個強大的功能權限與數據權限的授權體系
- 從底層開始,自動收集了系統的所有業務點(IFunction)和數據實體(IEntityInfo),用於對系統的功能權限、數據權限、數據緩存、操作審計 等實用功能提供數據支持。
- 功能點
Function與MVC的Area/Controller/Action一一對應,是功能權限的最小驗證單位,基於功能點,可以配置:- 功能訪問類型(匿名訪問、登錄訪問、限定角色訪問)
- 功能的數據緩存時間及緩存過期方式(絕對過期、相對過期)
- 是否開啟操作審計(XXX人員XXX時間做了XXX操作)
- 是否開啟數據審計(操作引起的數據變化詳情(新增、更新、刪除))
- 數據實體
EntityInfo與數據庫中的各個數據實體一一對應,基於數據實體,可以配置:- 是否開啟數據審計,與
Function上的同配置級別不同,如果指定實體未開放審計,則不審計當前實體。 - 實現數據權限,基於
角色 - 實體的數據權限設計,通過配置實現 XXX角色是否有權訪問XXX實體數據(的XX屬性)
- 是否開啟數據審計,與
- 設計了一個樹形結構的業務模塊體系(Module),對應着后端向前端(菜單/按鈕)開放的API,一個模塊可由一個或多個功能點構成,模塊是對外開放的特殊功能點,是進行 角色/用戶功能授權 的單位。把一個模塊授權給角色,角色即擁有了一個或多個功能點的操作權限。
功能權限授權流程
- [自動] 創建MVC的各個
Area/Controller/Action的功能點Function信息,存儲到數據庫 - [自動] 創建樹形模塊
Module信息,並創建模塊與功能點(一個或多個)的分配關系,存儲到數據庫 - 將模塊
Module分配給角色Role - 將角色
Role分配給用戶User - 可將模塊
Module分配給用戶User,解決特權問題 - 這樣用戶即可根據擁有的角色,自動擁有模塊對應着的所有功能點的功能權限

功能權限驗證流程
- 系統初始化時,根據每個角色
Role分配到的模塊Module,自動初始化每個角色 Role - Function[]的權限對應關系並緩存 - 游客進入系統時,自動請求所有可匿名訪問
FunctionAccessType.Anonymouse的模塊信息並緩存到瀏覽器,瀏覽器根據這個緩存的模塊集合,對前端頁面的各個操作點(菜單/按鈕)進行是否隱藏/禁用的狀態控制 - 注冊用戶登錄系統時,自動請求所有可執行(包括匿名的
FunctionAccessType.Anonymouse、登錄的FunctionAccessType.Logined、指定角色的FunctionAccessType.RoleLimit)的模塊信息並緩存到瀏覽器,瀏覽器根據這個緩存的模塊集合,對前端頁面的各個操作點(菜單/按鈕)進行是否隱藏/禁用的狀態控制

- 用戶
User執行一個功能點Function時,驗證流程如下:- 功能點不存在時,返回404
- 功能點被鎖定時,返回423
- 功能點可訪問性為匿名
FunctionAccessType.Anonymouse驗證通過 - 功能點可訪問性為需要登錄
FunctionAccessType.Logined時,用戶未登錄,返回401,已登錄則驗證通過 - 功能點可訪問性為需要登錄
FunctionAccessType.RoleLimit時,流程如下:- 用戶未登錄,返回401
- 逐個驗證用戶擁有的角色
Role,根據角色從緩存中取出Role-Function[]緩存項,Function[]包含要驗證的功能點時,驗證通過 - 由分配給用戶的模塊
Module對應的功能點,獲取到User-Function[](並緩存),Function[]包含要驗證的功能點時,驗證通過 - 驗證未通過,返回403

數據權限授權流程
- 基於 角色
Role-實體EntityInfo的一一對應關系,配置指定角色對指定數據實體的數據查詢篩選規則,並持久化到數據庫中 - 數據查詢篩選規則組成為 條件組
FilterGroup和條件FilterRule,一個條件組 FilterGroup 包含 一個或多個條件 FilterRule 和 一個或多個 條件組FilterGroup,這樣就實現了條件組和條件的無限嵌套,能滿足絕大多數數據篩選規則的組裝需要,如下圖:

數據權限驗證流程
- 系統初始化時,將所有
角色-實體的數據篩選規則緩存到內存中 - 進行數據查詢的時候,根據當前用戶的所有
角色 Role和要查詢的實體 EntityInfo,查找出所有配置的數據篩選規則FilterGroup,轉換為數據查詢表達式Expression<Func<TEntity,bool>>,各個角色的表達式之間使用Or邏輯進行組合 - 將以上生成的
數據權限數據查詢表達式,使用And邏輯組合到用戶的提交的查詢條件生成的表達式中,得到最終的數據查詢表達式,提交到數據庫中進行數據查詢,從而獲得數據權限限制下的合法數據
6. 集成 Swagger 后端API文檔系統
OSharp 快速啟動模板的開發模式,集成了Swagger API 文檔生成組件,更方便了前后端分離的開發模式中前后端開發人員的數據接口對接工作。基於Swagger的工作原理,API的輸入輸出都需使用強類型的數據類型,Swagger才能發揮更好的作用,而OSharp框架通過AutoMapper的ProjectTo對業務實體到輸出DTOIOutputDto提供了自動映射功能,能有效減輕后端開發中數據對象屬性映射的工作量。
界面展示
OSharp 的這個版本是基於Angular前端框架 NG-ALAIN 開發的,部分界面展示如下:
后台主頁:

功能管理:

數據實體管理:





































