软件即服务概念的推动,定制化到通用化的发展,用一套代码完成适应不同企业的需求,利用多租户技术可以去做到这一点。ABP里提供了多租户这一概念并且也在Zero模块中实现了这一概念。

一、多租户的概念

  单部署-单数据库:部署应用程序的单个实例和单个数据库。在每个数据表(关系型数据库)里用一个TenantId(租户Id或类似的如企业Id)字段来隔离区分每个租户数据。

  单部署-多数据库:部署应用的单一实例,用一个主(宿主)数据库存储租户元数据(像租户名和子域),并为每个租户建立并维护一个隔离的数据库。操作上通过识别当前租户并从主数据库中读取相对应的存储数据库地址,切换到该租户独有的数据库中执行操作。

  多部署-多数据库:为每个租户部署应用的一个实例并使用一个独立的数据库,那么我们就可以在一台服务器上为多个租户服务,只需确保相同应用的多个实例在一个服务器的环境下不会互相冲突就行。

  还有两种多租户形式,诸如单部署-混搭数据库、集群部署-单/多/混搭数据库,不再提及,ABP针对于这五种多租户形式都可以使用。

  宿主与租户:对于这两个概念,最好的理解方式便是酒店,酒店老板即是宿主,租户只拥有房间权限,酒店老板可以提供管理所有租户和房间。

二、ABP中多租户配置

1、启用/禁用多租户

  如果不需要多租户,比如说没有多租户情形,应用部署在企业私有服务器上,那么也可以不考虑多租户的使用,可以在ABP中关闭多租户(尽管关闭了,但默认还是会使用一个租户,默认租户Id为1,此时只有这个默认租户没有宿主)。在WebCoreModule中PreInitialize方法内可以添加如下代码启用或关闭多租户,默认是启用的。

public override void PreInitialize()
{
   ... Configuration.MultiTenancy.IsEnabled = true; ...
}

2、侦测当前租户并在Session中获取租户

 ABP中租户名称是唯一的,对于识别当前租户或是宿主身份,ABP没有使用Asp.Net 提供的Session,声明了IAbpSession接口并提供了默认的实现(ClaimAbpSession)去测定当前租户信息,按照如下思路去确定租户。

  • 如果当前用户登录了系统,那么可以从当前用户的声明信息中读取到当前租户信息,如果没有读取到租户信息,那么可以断定是宿主。
  • 如果当前用户没有登录系统,那么会有几种方式去获取,如果以下几种方式仍未获取到租户Id,则认为是使用宿主登录。
  • 从当前域名或是子域名去获取域名名称,然后通过租户仓储去查询是否存在相关的域名或子域名存在则可以确定租户Id。
  • 从Http请求头中获取在ABP中默认配置项Abp.TenantId(该配置项可更换名称)。
  • 从Http请求的cookie中获取Abp.TenantId

 IAbpSession声明了获取当前用户和租户信息的方法,该方法允许我们获取当前登录的用户及当前的租户信息。并且获取到的信息按照不同的规则,有着不同的作用。

  • 如果获取到的用户和租户Id都是空的,那么意味着当前用户没有登录系统,因此也无法断定出当前是宿主还是租户。
  • 如果用户Id是空的,但是租户Id不是空的,那么可以知道是哪个租户,但是用户仍然是没有登录的,只是选择了租户。
  • 如果用户Id不是空的,但是租户Id是空的,那么可以知道是用户使用宿主登录了系统。
  • 如果用户Id且租户Id不是空的,那么就知道是选择了租户并且是租户中的某个用户登录了系统。

3、数据过滤

  如果使用了多租户,那么在读取数据时,会依据当前租户Id加上额外的过滤条件,这一点ABP已经处理好了,我们无需在linq中敲代码,但是有个前提条件是,读取数据的这个实体有设置多租户。

  1、如果实体使用的是IMustHaveTenant接口,那么读取时会依照当前租户Id进行条件过滤。

  2、如果实体使用的是IMayHaveTenant接口,那么读取到的数据会依照当前租户Id的有无值进行区分,如果当前租户Id为空,那么将读取到宿主的数据,如果租户Id不为空,则读取相应租户数据。

  3、如果实体没使用这两个接口,则读取到的数据不区分宿主和租户。

  这两个接口使用场景:如果是宿主和租户都需要的,比如角色、用户、部门等,那么使用IMayHaveTenant接口,如果仅是租户所需要的那只需使用IMustHaveTenant接口。

4、宿主与租户间切换

  此处切换可以这么理解,给我一个其它租户Id,我可以在我的租户中获取到其它租户的数据,相应的,其它租户也可以获取到我租户的数据,或是宿主获取租户数据。如果不给定租户Id,租户可以获取宿主数据。

public class ProductService : ITransientDependency
{
private readonly IRepository<Product> _productRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager; public ProductService(IRepository<Product> productRepository, IUnitOfWorkManager unitOfWorkManager)
{
_productRepository = productRepository;
_unitOfWorkManager = unitOfWorkManager;
} [UnitOfWork]
public virtual List<Product> GetProducts(int tenantId)
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return _productRepository.GetAllList();
}
}
}

三、配置一个多租户实体

  基于之前的数据字典进行改造,以便适用于多个租户使用,并且考虑到宿主无需使用数据字典,将其继承IMustHaveTenant接口后,更新数据库便可。

public class DataDictionary : Entity<long>, IMustHaveTenant
{
public const int MaxNameLength = ; /// <summary>
/// 租户Id
/// </summary>
public int? TenantId { get; set; } /// <summary>
/// 字典类型
/// </summary>
[StringLength(MaxNameLength)]
public string TypeName { get; set; } /// <summary>
/// 关联数据字典项
/// </summary>
public virtual ICollection<DataDictionaryItem> DataDictionaryItem { get; set; }
}

  我设置了默认当前租户,并且不提供选择租户的页面,通过Url去区分宿主和默认租户,登录当前租户账号后,查看当前网站内的数据字典看到之前已有数据全部消失,获取数据字典数据时,默认是ABP将当前租户Id带入作为查询条件了。

  

  修改添加方法,添加当前租户Id的赋值,再次为当前租户添加几条相应的数据字典,页面中即可存在相关数据了。

dataDictionary.TenantId = AbpSession.TenantId.Value;

  最后两条数据是指定租户Id为1下的,之前的数据可以手动清除。

  

 至此,对于ABP中租户的相关使用了解的清楚了,对于多租户下数据存储量大,拆分成集群部署-多数据库情形没有做尝试,希望有机会可以使用一番。

 仓库地址:https://gitee.com/530521314/Partner.Surround.git

2020-01-11,望技术有成后能回来看见自己的脚步

X-Admin&ABP框架开发-租户管理的更多相关文章

  1. X-Admin&ABP框架开发-设置管理

    在网站开发中,设置是不可缺少的一环,如用户设置.系统设置.甚至是租户设置等.ABP对于设置的管理已经做了很好的处理,我们可以借助巨人的力量来完成我们的冒险. ABP官网地址:https://aspne ...

  2. ABP Zero 多租户管理

    ABPZero - 多租户管理 启用多租户 ASP.NET Boilerplate和module-zero可以运行多租户或单租户模式.多租户默认为禁用.我们可以在我们的模块PreInitialize方 ...

  3. X-Admin&ABP框架开发-RBAC

    在业务系统需求规划过程中,通常对于诸如组织机构.用户和角色等这种基础功能,通常是将这部分功能规划到通用子域中,这也说明了,对于这部分功能来讲,是系统的基石,整个业务体系是建立于这部分基石之上的,当然, ...

  4. X-Admin&ABP框架开发-版本管理

    多租户系统中,针对于不同租户开放不同功能,或是按照不同功能进行收费管理,需要从宿主本身去管理租户的版本信息,如同酒店人员对不同房间收取不同费用,依据房间内部设施,房间大小等设置不同收费标准.Abp系统 ...

  5. X-Admin&ABP框架开发-消息通知

    业务型网站使用过程中,消息通知是一个不可或缺的功能,采用站内通知.短信通知.邮件通知.微信通知等等各种方式都有,ABP框架对这部分工作已经封装的很好了,站在巨人的肩膀上,一览全貌,带来的就是心情舒畅. ...

  6. X-Admin&ABP框架开发-系统日志

    网站正常运行中有时出现异常在所难免,查看系统运行日志分析问题并能够根据错误信息快速解决问题尤为重要,ABP对于系统运行日志这块已经做了很好的处理,默认采用的Log4Net已经足够满足开发过程中的需要了 ...

  7. ABP框架 - 多租户

    文档目录 本节内容: 什么是多租户 多部署 - 多数据库 单部署 - 多数据库 单部署 - 单数据库 单部署 - 混数据库 多部署 - 单/多/混 数据库 ABP中的多租户 启用多租户 宿主与租户 会 ...

  8. X-Admin&ABP框架开发-代码生成器

    在日常开发中,有时会遇到一些相似的代码,甚至是只要CV一次,改几个名称,就可以实现功能了,而且总归起来,都可以由一些公用的页面更改而来,因此,结合我日常开发中使用到的页面,封装一个适合自己的代码生成器 ...

  9. X-Admin&ABP框架开发-数据字典

    在业务型的系统开发中,我们需要维护各种个样的类型,比如客户类型.客户行业.商品类型等等,这些类型往往信息量不多,并且相似度极高,如果采用一类型一表去设计,将会造成极大的工作量,通过将这部分类型的信息进 ...

随机推荐

  1. 【codeforces 520A】Pangram

    [题目链接]:http://codeforces.com/problemset/problem/520/A [题意] 给你一个字符串. 统计里面有没有出现所有的英文字母->'a'..'z' 每个 ...

  2. 洛谷P4136 谁能赢呢? 题解 博弈论

    题目链接:https://www.luogu.org/problem/P4136 找规律 首先这道题目我没有什么思路,所以一开始想到的是通过搜索来枚举 \(n\) 比较小的时候的情况. 所以我开搜索枚 ...

  3. Vue 路由的嵌套使用

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Native memory allocation (mmap) failed to map xxx bytes for committing reserved memory

    遇到问题 在服务器上运行 nexus 出现Native memory allocation (mmap) failed to map 838860800 bytes for committing re ...

  5. java基本类型和String之间的转换

    String → 基本类型,除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量: 基本类型 → String,String ...

  6. P1020 从大到小排序

    题目描述 给你n个整数,请你按照从大到小的顺序输出它们. 输入格式 输入的第一行包含一个整数 \(n(1 \le n \le 10^3)\) ,用于表示元素的个数. 输入的第二行包含 \(n\) 个整 ...

  7. H3C 配置静态及动态域名解析

  8. vue-learning:0 - 目录

    Vue-learning vue.js学习路径 Vue的API地图 点击查看vue的API地图 视图层 点击可直接到达详情页面 指令 {{ }} / v-html v-if / v-else / v- ...

  9. vue-router再学习

    vue路由: 1:动态路由配置 import Vue from 'vue' import Router from 'vue-router' import Index from '@/view/inde ...

  10. gulp4.0基本配置,超简单!

    最近复习了一下gulp,目前是4.0版本. 下图是基本目录结构,文件里面的内容可以随意添加,超详细简洁啊! 直接上代码(依赖未完全使用): 项目的所有依赖都可以安装,每个都有详细的注释. const ...