ServiceStack 多租户的实现方案
以SqlServer为例子说明ServiceStack实现多租户,在SqlServer中创建4个Database:TMaster、T1,T2,T3,为了安全起见
每个Database不用sa账号,而是用独立的数据库的账号和密码,为了方便演示这密码设置成一样
租户TMaster Database:TMaster 账号密码: User Id=TMaster;Password=t123
租户T1 Database:T1 账号密码: User Id=T1;Password=t123
租户T2 Database:T2 账号密码: User Id=T2;Password=t123
租户T3 Database:T3 账号密码: User Id=T3;Password=t123
创建数据库的方法可以参见文章: https://www.cnblogs.com/tonge/p/3791029.html
每个登陆用自己的账号和密码登陆,其它的数据库是没有访问权限的,这个各个租户是完全隔离的。
假设Node和npm已经安装
npm install -g @servicestack/cli
执行命令dotnet-new selfhost SSHost
这样就创建了ServiceStack的控制台程序,用VS2017解决方案,在ServiceModel的Types文件夹添加TenantConfig类文件
代码如下:
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ssTest.ServiceModel.Types
- {
- public interface IForTenant
- {
- string TenantId { get; }
- }
- public class TenantConfig
- {
- public string Id { get; set; }
- public string Company { get; set; }
- }
- }
修改Hello.cs文件,代码如下:
- using ServiceStack;
- using ssTest.ServiceModel.Types;
- using System;
- namespace ssTest.ServiceModel
- {
- [Route("/hello")]
- [Route("/hello/{Name}")]
- public class Hello : IForTenant, IReturn<HelloResponse>
- {
- public string Name { get; set; }
- // 实现接口IForTenant(租户标识Id)
- public string TenantId { get; set; }
- }
- public class HelloResponse
- {
- public string Result { get; set; }
- public DateTime Date { get; set; }
- // 返回租户公司信息
- public TenantConfig Config { get; set; }
- }
- }
主程序的Startup代码如下
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- }
- public void Configure(IApplicationBuilder app, IHostingEnvironment env)
- {
- // JsConfig.DateHandler = DateHandler.ISO8601;
- // 保证时间类型的字段可以解析成js识别的时间类型
- JsConfig<DateTime>.SerializeFn = time => new DateTime(time.Ticks, DateTimeKind.Local).ToString("o");
- JsConfig<DateTime?>.SerializeFn =
- time => time != null ? new DateTime(time.Value.Ticks, DateTimeKind.Local).ToString("o") : null;
- JsConfig.DateHandler = DateHandler.ISO8601;
- app.UseServiceStack(new AppHost());
- app.Run(context =>
- {
- context.Response.Redirect("/metadata");
- return Task.FromResult();
- });
- }
- }
下面就到核心代码了,在主程序中建立多租户Db工程类,让程序可以自动的根据租户Id访问自己的数据库
- public class MultiTenantDbFactory : IDbConnectionFactory
- {
- private readonly IDbConnectionFactory dbFactory;
- public MultiTenantDbFactory(IDbConnectionFactory dbFactory)
- {
- this.dbFactory = dbFactory;
- }
- public IDbConnection OpenDbConnection()
- {
- var tenantId = RequestContext.Instance.Items["TenantId"] as string;
- return OpenTenant(tenantId);
- }
- public IDbConnection OpenTenant(string tenantId = null)
- {
- return tenantId != null
- ? dbFactory.OpenDbConnectionString($"Data Source=.; Initial Catalog={tenantId};User Id={tenantId};Password=t123;pooling=true;")
- : dbFactory.OpenDbConnection();
- }
- public IDbConnection CreateDbConnection()
- {
- return dbFactory.CreateDbConnection();
- }
- }
AppHost中加入如下代码,GlobalRequestFilters的作用,根据传入的租户Id来选择相应的数据库,如果租户Id为null,系统自动使用TMaster数据库
InitDb的作用就是初始化三个数据库,创建表TenantConfig并插入一条记录。
- public override void Configure(Container container)
- {
- ConigureSqlserver(container);
- }
- private void ConigureSqlserver(Container container)
- {
- var dbFactory = new OrmLiteConnectionFactory(
- "Data Source=.; Initial Catalog=TMaster;User Id=TMaster;Password=t123;pooling=true;", SqlServerDialect.Provider);
- const int noOfTennants = ;
- container.Register<IDbConnectionFactory>(c =>new MultiTenantDbFactory(dbFactory));
- var multiDbFactory = (MultiTenantDbFactory)container.Resolve<IDbConnectionFactory>();
- using (var db = multiDbFactory.OpenTenant())
- InitDb(db, "TMaster", "Masters inc.");
- for(int i=; i<= noOfTennants; i++)
- {
- var tenantId = $"T{i}";
- using (var db = multiDbFactory.OpenTenant(tenantId))
- InitDb(db, tenantId, $"ACME {tenantId} inc.");
- }
- GlobalRequestFilters.Add((req, res, dto) =>
- {
- var forTennant = dto as IForTenant;
- if (forTennant != null)
- RequestContext.Instance.Items.Add("TenantId", forTennant.TenantId);
- });
- }
- public void InitDb(IDbConnection db, string tenantId, string company)
- {
- db.DropAndCreateTable<TenantConfig>();
- db.Insert(new TenantConfig { Id = tenantId, Company = company });
- }
这样核心代码就完成了,我们用postman调用试试看,是不是达到了预期的效果
body为空,租户Id没有设置,系统认为是默认的数据库TMaster,返回的是Master数据库中的config表信息
body中设置json参数{"name":"joy", "tenantId":"t1"},可以看到查询返回的是数据库T1的信息
我们再试验一下T2,body中设置json参数{"name":"peter", "tenantId":"t2"}
可以很惊喜的看到,查询的是数据库T2的信息
ServiceStack解决方案真是强大,本来一个复杂的多租户问题就这样轻易解决了,是不是很简单。这里例子用的都是sqlserver数据库,实际上每个租户可以使用不同的数据库。
最近一年很流行ABP解决方案,我想说的是ServiceStack解决方案也很优秀,甚至更加优秀,当你了解越多你就会惊叹当初作者的设计思路是多么的优秀,有兴趣的小伙伴可以一起挖掘和分享啊!
ServiceStack 多租户的实现方案的更多相关文章
- 多租户SaaS平台的数据库方案
1.1 多租户是什么 多租户技术(Multi-TenancyTechnology)又称多重租赁技术:是一种软件架构技术,是实现如何在多用户环境下 (此处的多用户一般是面向企业用户)共用相同的系统或程序 ...
- 实现saas多租户方案比较
看到一篇比较多租户数据隔离方案的文章,总结挺不错.其实大部分内容在我前几年写的文章都有. 文章翻译自: https://blog.arkency.com/comparison-of-approache ...
- 数据层的多租户浅谈(SAAS多租户数据库设计)
在上一篇“浅析多租户在 Java 平台和某些 PaaS 上的实现”中我们谈到了应用层面的多租户架构,涉及到 PaaS.JVM.OS 等,与之相应的是数据层也有多租户的支持. 数据层的多租户综述 多租户 ...
- EF Core 实现多租户
目录 SAAS 和多租户 多租户数据隔离方案 使用 EF Core 简单实现多租户 单数据库实现 多数据库实现 源代码 参考 SAAS 和多租户 SaaS(软件及服务)区别于其他应用程序的主要特征就是 ...
- 在 Windows Azure 上设计多租户应用程序
作者:Suren Machiraju 和 Ralph Squillace 审校:Christian Martinez.James Podgorski.Valery Mizonov 和 Michael ...
- [转载]数据层的多租户浅谈(SAAS多租户数据库设计)
原文:http://www.ibm.com/developerworks/cn/java/j-lo-dataMultitenant/index.html 在上一篇“浅析多租户在 Java 平台和某些 ...
- 一种Django多租户解决方案
什么是多租户? 多租户技术或称多重租赁技术,简称SaaS,是一种软件架构技术,是实现如何在多用户环境下(此处的多用户一般是面向企业用户)共用相同的系统或程序组件,并且可确保各用户间数据的隔离性. 多租 ...
- 如何在多模型的情况下进行EF6的结构迁移
所谓多模型就是在一个数据库中包含两个不同模型,或者换句话说就是两个不同DbContext的数据都放到同一个数据库中.这里的多模型不是指多租户的数据库(有谁知道EF很好处理多租户数据库的方案,可以联系我 ...
- DAL – RDBMS 的分区
编辑人员注释:本文章由AzureCAT 云与企业工程组的高级项目经理Shaun Tinline-Jones 和Chris Clayton 共同撰写. "云服务基础"应用程序也称作& ...
随机推荐
- sqli-labs:17,增删改
增 insert into users values(','lcamry','lcamry'); 删 delete from users where id=16 删数据库:drop database ...
- 爬虫初窥day2:正则
正则在线测试 http://tool.oschina.net/regex https://www.regexpal.com/ http://tool.chinaz.com/regex exp1:筛选所 ...
- IOS初级:app的图标
1,首先准备6张png图,分辨率一定要正确,不然报错(The app icon set named "AppIcon" did not have any applicable co ...
- java script入门之知识
1.注释 /* */ 多行 //单行 2.常见形式 <!DOCTYPE html><html><head><title>My ...
- OneZero第三周第四次站立会议(2016.4.7)
1. 时间: 18:35--18:50 共计15分钟. 2. 成员: X 夏一鸣 * 组长 (博客:http://www.cnblogs.com/xiaym896/), G 郭又铭 (博客:http: ...
- idea下使用lombok
转载 https://blog.csdn.net/u013177446/article/details/53943365 (1)pom引入依赖 <dependency> <group ...
- XML 解析的两种方法
申请博客有一段时间了,一直没有写些什么,今天写一下被遗忘的 xml,因为 ios 现在一般都用 JSON,但毕竟还有一部分老一些的服务器还会有 xml xml 格式的解析方式有两种 1.SAX解析: ...
- thymeleaf使用基础教程
thymeleaf 是新一代的模板引擎,在spring4.0中推荐使用thymeleaf来做前端模版引擎. thymeleaf介绍 简单说, Thymeleaf 是一个跟 Velocity.FreeM ...
- 2018.11.06 bzoj1093: [ZJOI2007]最大半连通子图(缩点+拓扑排序)
传送门 先将原图缩点,缩掉之后的点权就是连通块大小. 然后用拓扑排序统计最长链数就行了. 自己yyyyyy了一下一个好一点的统计方法. 把所有缩了之后的点都连向一个虚点. 然后再跑拓扑,这样最后虚点的 ...
- poj--2299(树状数组+离散化)
一.离散化: https://www.cnblogs.com/2018zxy/p/10104393.html 二.逆序数 AC代码: #include<iostream> #include ...