Fork me on GitHub

[开源]OSharpNS - .net core 快速开发框架 - 简介

什么是OSharp

OSharpNS全称OSharp Framework with .NetStandard2.0,是一个基于.NetStandard2.0开发的一个.NetCore快速开发框架。这个框架使用最新稳定版的.NetCore SDK(当前是.NET Core 2.2),对 AspNetCore 的配置、依赖注入、日志、缓存、实体框架、Mvc(WebApi)、身份认证、权限授权等模块进行更高一级的自动化封装,并规范了一套业务实现的代码结构与操作流程,使 .Net Core 框架更易于应用到实际项目开发中。

框架工程组织

框架的工程组织结构如下:

框架工程组织结构

各工程简介

  1. OSharp【框架核心组件】:框架的核心组件,包含一系列快速开发中经常用到的Utility辅助工具功能,框架各个组件的核心接口定义,部分核心功能的实现
  2. OSharp.AspNetCore【AspNetCore组件】:AspNetCore组件,提供AspNetCore的服务端功能的封装
  3. OSharp.AutoMapper【对象映射组件】:AutoMapper 对象映射组件,封装基于AutoMapper的对象映射实现
  4. OSharp.EntityFrameworkCore【EFCore 数据组件】:EFCore数据访问组件,封装EntityFrameworkCore数据访问功能的实现
  5. OSharp.EntityFrameworkCore.MySql【EFCore MySql 数据组件】:EFCore MySql数据访问组件,封装MySql的EntityFrameworkCore数据访问功能的实现
  6. OSharp.EntityFrameworkCore.SqlServer【EFCore SqlServer 数据组件】:EFCore SqlServer数据访问组件,封装SqlServer的EntityFrameworkCore数据访问功能的实现
  7. OSharp.EntityFrameworkCore.Sqlite【EFCore Sqlite 数据组件】:EFCore Sqlite数据访问组件,封装Sqlite的EntityFrameworkCore数据访问功能的实现
  8. OSharp.EntityFrameworkCore.PostgreSql【EFCore PostgreSql 数据组件】:EFCore PostgreSql数据访问组件,封装PostgreSql的EntityFrameworkCore数据访问功能的实现
  9. OSharp.EntityFrameworkCore.Oracle【EFCore PostgreSql 数据组件】:EFCore Oracle数据访问组件,封装Oracle的EntityFrameworkCore数据访问功能的实现
  10. OSharp.Permissions【权限组件】:使用AspNetCore的Identity为基础实现身份认证的封装,以Security为基础实现以角色-功能、用户-功能的功能权限实现,以角色-数据,用户-数据的数据权限的封装
  11. OSharp.Log4Net【日志组件】:基于Log4Net的日志记录组件
  12. OSharp.Redis【缓存组件】:基于Redis的分布式缓存客户端组件
  13. OSharp.Hangfire【后台任务组件】:封装基于Hangfire后台任务的服务端实现
  14. OSharp.MiniProfiler【MiniProfiler组件】:基于MiniProfiler实现的性能监测组件
  15. OSharp.Swagger【SwaggerAPI组件】:基于Swagger生成MVC的Action的API测试接口信息
  16. OSharp.Exceptionless【Exceptionless分布式日志组件】:封装基于Exceptionless 分布式日志记录实现

Nuget Packages

包名称 Nuget版本 下载数
OSharpNS.Core OSharpNS.Core OSharpNS.Core
OSharpNS.AspNetCore OSharpNS.AspNetCore OSharpNS.AspNetCore
OSharpNS.AutoMapper OSharpNS.AutoMapper OSharpNS.AutoMapper
OSharpNS.EntityFrameworkCore OSharpNS.EntityFrameworkCore OSharpNS.EntityFrameworkCore
OSharpNS.EntityFrameworkCore.SqlServer OSharpNS.EntityFrameworkCore.SqlServer OSharpNS.EntityFrameworkCore.SqlServer
OSharpNS.EntityFrameworkCore.MySql OSharpNS.EntityFrameworkCore.MySql OSharpNS.EntityFrameworkCore.MySql
OSharpNS.EntityFrameworkCore.Sqlite OSharpNS.EntityFrameworkCore.Sqlite OSharpNS.EntityFrameworkCore.Sqlite
OSharpNS.EntityFrameworkCore.PostgreSql OSharpNS.EntityFrameworkCore.PostgreSql OSharpNS.EntityFrameworkCore.PostgreSql
OSharpNS.EntityFrameworkCore.Oracle OSharpNS.EntityFrameworkCore.Oracle OSharpNS.EntityFrameworkCore.Oracle
OSharpNS.Permissions OSharpNS.Permissions OSharpNS.Permissions
OSharpNS.Log4Net OSharpNS.Log4Net OSharpNS.Log4Net
OSharpNS.Redis OSharpNS.Redis OSharpNS.Redis
OSharpNS.Hangfire OSharpNS.Hangfire OSharpNS.Hangfire
OSharpNS.Exceptionless OSharpNS.Exceptionless OSharpNS.Exceptionless
OSharpNS.MiniProfiler OSharpNS.MiniProfiler OSharpNS.MiniProfiler
OSharpNS.Swagger OSharpNS.Swagger OSharpNS.Swagger
OSharpNS OSharpNS OSharpNS
OSharpNS.Template.Mvc_Angular OSharpNS.Template.Mvc_Angular OSharpNS.Template.Mvc_Angular

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. 自动化的依赖注入注册机制

空接口标注方式

框架定义了ISingletonDependencyIScopeDependencyITransientDependency 三个空接口,对应着依赖注入的ServiceLifetime.SingletonServiceLifetime.ScopedServiceLifetime.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框架通过AutoMapperProjectTo对业务实体到输出DTOIOutputDto提供了自动映射功能,能有效减轻后端开发中数据对象属性映射的工作量。

界面展示

OSharp 的这个版本是基于Angular前端框架 NG-ALAIN 开发的,部分界面展示如下:

后台主页:

功能管理:

数据实体管理:

posted @ 2019-05-05 09:55  郭明锋  阅读(...)  评论(...编辑  收藏