OSharpNS簡介
OSharp Framework with .NetStandard2.0(OSharpNS)是OSharp的以.NetStandard2.0
為目標框架,在AspNetCore
的現有組件 Microsoft.Extensions.DependencyInjection
,Microsoft.Extensions.Configuration
,
Microsoft.Extensions.Logging
,Microsoft.Extensions.Caching
,Microsoft.EntityFrameworkCore
等 上進行構建的快速開發框架。
框架目標人群
本框架適用於中小型項目,一(兩)年以上開發經驗,對依賴注入,ORM,緩存,日志,發布訂閱模式有一定理解的開發人員
框架組件組織
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.PostgreSql
【EFCore PostgreSql 數據組】:EFCore PostgreSql數據訪問組件,封裝PostgreSql的EntityFrameworkCore數據訪問功能的實現OSharp.EntityFrameworkCore.Sqlite
【EFCore Sqlite 數據組】:EFCore Sqlite數據訪問組件,封裝Sqlite的EntityFrameworkCore數據訪問功能的實現OSharp.EntityFrameworkCore.SqlServer
【EFCore SqlServer 數據組件】:EFCore SqlServer數據訪問組件,封裝SqlServer的EntityFrameworkCore數據訪問功能的實現OSharp.EntityFrameworkCore.Sqlite
【EFCore Sqlite 數據組件】:EFCore Sqlite數據訪問組件,封閉Sqlite的EntityFrameworkCore數據訪問功能的實現OSharp.Exceptionless
【Exceptionless 分布式日志組件】:Exceptionless 分布式日志組件,封裝基於Exceptionless 分布式日志記錄實現OSharp.Hangfire
【Hangfire后台任務組件】:Hangfire 后台任務組件,封裝基於Hangfire后台任務的服務端實現OSharp.Log4Net
【Log4Net組件】:Log4Net組件,封裝使用log4net組件來實現框架的日志輸出功能OSharp.MiniProfiler
【MiniProfiler 性能監測組件】:MiniProfiler 性能監測組件,基於MiniProfiler實現的性能監測組件OSharp.Permissions
【權限組件】:使用AspNetCore的Identity為基礎實現身份認證的封裝,以Security為基礎實現以角色-功能、用戶-功能的功能權限實現,以角色-數據,用戶-數據的數據權限的封裝OSharp.Redis
【Redis 緩存組件】:Redis 緩存組件,封裝基於Redis客戶端的緩存實現OSharp.Swagger
【Swagger 客戶端組件】:Swagger 客戶端組件,封裝基於Redis客戶端實現
OSharpNS特性
1. 模塊化的組件設計
框架設計了一個模塊(Pack)的系統,所有實現了模塊基類(OsharpPack)的類都視為一個獨立的模塊,一個模塊可以獨立添加服務(AddServices),並可在初始化時應用服務(UsePack)進行模塊初始化。
2. 自動化的依賴注入機制
框架定義了ISingletonDependency
,IScopeDependency
,ITransientDependency
三個空接口對應DependencyInjection中的三種服務生命周期,系統初始化時,通過反射檢索程序集的方式,檢索出所有服務類型(ServiceType)與服務實現(ImplementationType)及生命周期類型(ServiceLifetime)的相關數據,對依賴注入的ServiceCollection進行全自動初始化。
3. UnitOfWork-Repository模式,EFCore上下文動態構建
- 數據模塊使用了
UnitOfWork-Repository
的模式來設計,設計了一個泛型的實體倉儲接口IRepository<TEntity,TKey>
,避免每個實體都需實現一個倉儲的繁瑣操作。設計了IUnitOfWork
接口來管理事務,通過UnitOfWork模式管理DbContext的創建,使不同上下文類型同數據庫連接字符串的上下文使用相同DbConnection對象來創建,達到多上下文的事務同步能力。 - 基於MVC的
ActionFilter
的UnitOfWorkAttribute
AOP 事務自動提交,業務中不再需要關心事務的生命周期。 - 系統初始化時,通過反射檢索程序集的方式,檢索出各個實體與上下文的映射關系,向上下文中動態添加實體類來構建上下文類型,以達到上下文類型與業務實體解耦的目的。通過統一基類
EntityTypeConfigurationBase<TEntity, TKey>
的FluentAPI實體映射,自由配置每個實體與數據庫映射的每一個細節。
4. 基於AspNetCore的Identity的身份認證設計系統
- 使用AspNetCore原生的用戶身份認證框架,身份認證相關操作統一使用
UserManager<TUser>
,RoleMamanger<TRole>
兩個入口,保持了原生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),對應着后端向前端開放的操作點(菜單/按鈕),一個模塊可由一個或多個功能點構成,模塊是對外開放的特殊功能點,是進行角色/用戶功能授權的單位。把一個模塊授權給角色,角色即擁有了一個或多個功能點的操作權限。
-
功能權限授權流程
- [自動] 創建MVC的各個
Area/Controller/Action
的功能點Function
信息,存儲到數據庫 - [自動] 創建樹形模塊
Module
信息,並創建模塊與功能點(一個或多個)的分配關系,存儲到數據庫 - 將模塊
Module
分配給角色Role
- 將角色
Role
分配給用戶User
- 可將模塊
Module
分配給用戶User
,解決特權問題 - 這樣用戶即可根據擁有的角色,自動擁有模塊對應着的所有功能點的功能權限
- [自動] 創建MVC的各個
-
功能權限驗證流程
- 系統初始化時,根據每個角色
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文檔系統
OSharpNS 快速啟動模板的開發模式,集成了Swagger
API 文檔生成組件,更方便了前后端分離的開發模式中前后端開發人員的數據接口對接工作。基於Swagger
的工作原理,API的輸入輸出都需使用強類型
的數據類型,Swagger
才能發揮更好的作用,而OSharpNS框架通過AutoMapper
的ProjectTo
對業務實體到輸出DTOIOutputDto
提供了自動映射功能,能有效減輕后端開發中數據對象屬性映射的工作量。
快速啟動
OSharpNS框架制作了一個基於dotnet cli
命令行工具的快速啟動模板,下面演示如何來使用這個模板快速創建一個基於OSharpNS框架的初始化項目。
1. 安裝最新版本 dotnetcore sdk
OSharpNS當前版本(0.2.1-beta05)使用了 dotnetcore
當前最新版本 2.1.1
,所以對應的 dotnetcore sdk
需要安裝到對應版本 >=v2.1.301。
2. 安裝OSharpNS的 dotnet new 項目模板
在任意空白目錄,打開cmd
或者powershell
命令行窗口,執行命令
dotnet new -i OSharpNS.Template.Mvc_Angular
執行后,將能看到osharp_xxx
系列的命令已安裝到列表中
3. 執行 osharp_cmd 命令,獲取項目一鍵安裝腳本
dotnet new osharp_cmd
執行后,將得到一個名為cmd_build.bat
的批處理腳本文件
4. 運行腳本文件,生成項目初始化代碼
直接執行cmd_build.bat
腳本代碼,將會提示 請輸入項目名稱,推薦形如 “公司.項目”的模式:
,此名稱將用作解決方案名稱、工程名稱起始部分、代碼中的namespace
起始部分。例如輸入Liuliu.Demo
,將生成如下代碼結構:
5. 用VS打開解決方案
打開解決方案后,各個工程之間的引用關系已配置好,osharp框架的類庫已引用 nuget.org 上的相應版本,並將自動還原好。項目結構如圖所示:
項目代碼結構說明:
Liuliu.Demo.Core
: 業務核心工程,頂層文件夾以業務模塊內聚,每個文件夾按職責划分文件夾,通常可包含傳輸對象Dtos
、實體類型Entities
、事件處理Events
等,業務接口IXxxContract
與業務實現IXxxService
放在外邊,如果文件數量多的話也可以建文件夾存放。Liuliu.Demo.EntityConfiguration
: EFCore實體映射工程,用於配置各個業務實體映射到數據庫的映射細節。文件夾也推薦按模塊內聚。Liuliu.Demo.Web
: 網站的Hosting項目,按常規方式使用即可
項目啟動配置
- 按實際環境修改配置文件
appsetting.Development.json
中的OSharp:DbContexts:[SqlServer|MySql]
中的配置信息,ConnectionString
為數據庫連接串,AutoMigrationEnabled
為是否開啟自動遷移 - 如未開啟
AutoMigrationEnabled
的自動遷移功能,還需要在nuget 控制台
手動執行遷移操作
Update-Database
- 配置好后,即可正常啟動端口號為
7001
的項目,啟動后開發模式將進入Swagger
的后端Api接口的文檔頁。
6. Angular6的前端項目啟動
前端項目使用了ng-alain
和kendoui
作為UI進行開發的,需要熟悉nodejs
,angular6
等技術。
安裝 NodeJS ,搭建前端技術環境
- 安裝最新版本 NodeJS:angular6需要最新版本的 NodeJS,請到 NodeJS官方網站 下載最新版本的NodeJS進行安裝。
- 設置npm的淘寶鏡像倉庫:由於npm的國外倉儲會很慢,所以最好把npm倉庫地址指定國內鏡像,推薦淘寶鏡像:
npm config set registry https://registry.npm.taobao.org
- 安裝全局Angular/Cli:如果Angular/Cli沒有安裝,執行如下命令全局安裝Angular
Angular的快速啟動,請參考Angular官方文檔
npm install -g @angular/cli
- 下載安裝 Visual Studio Code:前端最好用的IDE,官方下載
使用 VS Code 打開 Angular 前端項目
- 定位到項目的目錄
src/ui/ng-alain
,在空白處點右鍵,使用 VS Code 打開項目,可看到如下結構:
- 按
Ctrl+Tab
快捷鍵,調出VS Code的命令行控制台,輸入NodeJS包安裝命令:
npm install
- 包安裝完成后,輸入項目啟動命令:
npm start
此命令將會執行如下命令:ng serve --port 4201 --proxy-config proxy.config.json --open
,其中--proxy-config proxy.config.json
對前端項目發起的API請求進行了代理,所有以 /api/
開頭的請求,都會轉發到服務端項目中進行處理,代理的實際配置如下:
{
"/api": {
"target": "http://localhost:7001",
"secure": false
}
}
至此,項目啟動完成,后續可以進行用戶注冊的工作,請注意:
系統的第一個注冊用戶,將自動擁有系統最高權限的
超級管理員
權限
最終效果如下圖所示:
# 項目開發進度
截止到目前,OSharpNS 框架的完成程度已經很高了,計划中的功能點,除了數據權限
未完成,其余均已得到較高水准的實現,具體功能點完成進度如下所示:
- [ ] OSharpNS Framework
- [ ] OSharp
- [x] 添加常用Utility輔助工具類
- [x] 添加框架配置Options定義
- [x] 定義Entity數據訪問相關接口
- [x] 定義依賴注入模塊相關接口
- [x] 定義並實現EventBus事件總線的設計
- [x] 定義Mapper對象映射模塊相關接口
- [x] 定義實體信息EntityInfo及初始化,用於給各個實體進行數據日志審計配置及數據權限設計
- [x] 定義功能點信息Function及初始化,用於收集各個業務功能點(如MVC的Action),用於對功能進行緩存配置、操作日志審計、功能權限設計
- [x] 定義Permissions權限模塊的相關接口
- [x] 實現框架依賴注入服務啟動入口,調用各個功能模塊(Pack)添加各模塊的服務映射
- [x] 實現ServiceLocator服務定位模式的依賴注入對象的解析
- [x] OSharp.EntityFrameworkCore
- [x] 實現運行時上下文類型初始化及自動加載相關實體類型的功能
- [x] 實現Repository倉儲的數據存儲功能
- [x] 實現UnitOfWork的多上下文管理及同DbConnection的上下文事務同步
- [x] OSharp.AutoMapper
- [x] 不同的映射類型,通過實現
Profile
來實現映射注冊 - [x] 實現通過遍歷程序集,查找實現了
IMapTuple
接口的Profile
來自動注冊映射策略 - [x] 定義
MapToAttribute
,MapFromAttribute
類型,用以標注Mapping的Source與Target類型,使用時在要映射的類型上標注如[MapTo(typeof(TTarget))]
或[MapFrom(typeof(TSource))]
特性,框架初始化時自動查找相應的類型進行CreateMap映射注冊
- [x] 不同的映射類型,通過實現
- [x] OSharp.AspNetCore
- [x] AspNet
- [x] 實現框架啟動入口
app.UseOSharp()
,調用Pack模塊管理器OSharpPackManager
啟動各個功能模塊(OSharpPack) - [x] 實現基於當前請求的ServiceLocator的Scoped對象的解析
- [x] 實現JSON請求的404處理中間件
- [x] 實現JSON請求的異常信息到JSON操作結果與異常日志記錄中間件
- [x] 實現框架啟動入口
- [x] MVC
- [x] 添加Api專用控制器基類
ApiController
,AreaApiController
- [x] 實現MVC功能點處理器
- [x] 實現MVC業務模塊處理器
- [x] 實現基於MVC的功能權限AOP攔截驗證
- [x] 實現基於MVC的事務提交AOP攔截提交
- [x] 添加Api專用控制器基類
- [x] SignalR
- [x] 定義客戶端連接與用戶信息的對應關系
ConnectionUser
- [x] 實現客戶端連接與用戶信息的緩存
IConnectionUserCache
- [x] 定義客戶端連接與用戶信息的對應關系
- [x] AspNet
- [ ] OSharp.Permissions
- [x] 身份認證Identity
- [x] 用戶添加昵稱
NickName
屬性,並添加默認驗證器 - [x] 重寫UserStore,RoleStore,使用現有IRepository進行數據存儲
- [x] 用戶添加昵稱
- [ ] 權限授權Security
- [x] 功能權限
- [x] 實現功能權限各個業務實體的數據存儲
- [x] 實現在系統初始化時,遍歷反射程序集,自動初始化功能點、數據實體、業務模塊等信息並持久化到數據庫
- [x] 實現系統初始化時,將功能點,數據實體,角色功能權限等信息緩存到內存中
- [x] 實現
角色-功能點
,用戶-功能點
的功能權限驗證
- [ ] 數據權限
- [ ] 實現
角色-實體
,用戶-實體
的數據權限配置 - [ ] 實現
角色-實體
,用戶-實體
的數據權限過濾
- [ ] 實現
- [x] 功能權限
- [x] 系統System
- [x] 實現鍵值對數據字典功能
- [x] 身份認證Identity
- [ ] OSharp