以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类文件

代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4.  
  5. namespace ssTest.ServiceModel.Types
  6. {
  7. public interface IForTenant
  8. {
  9. string TenantId { get; }
  10. }
  11.  
  12. public class TenantConfig
  13. {
  14. public string Id { get; set; }
  15.  
  16. public string Company { get; set; }
  17. }
  18. }

修改Hello.cs文件,代码如下:

  1. using ServiceStack;
  2. using ssTest.ServiceModel.Types;
  3. using System;
  4.  
  5. namespace ssTest.ServiceModel
  6. {
  7. [Route("/hello")]
  8. [Route("/hello/{Name}")]
  9. public class Hello : IForTenant, IReturn<HelloResponse>
  10. {
  11.  
  12. public string Name { get; set; }
  13.  
  14. // 实现接口IForTenant(租户标识Id)
  15. public string TenantId { get; set; }
  16. }
  17.  
  18. public class HelloResponse
  19. {
  20. public string Result { get; set; }
  21.  
  22. public DateTime Date { get; set; }
  23.  
  24. // 返回租户公司信息
  25. public TenantConfig Config { get; set; }
  26. }
  27. }

主程序的Startup代码如下

  1. public class Startup
  2. {
  3. public void ConfigureServices(IServiceCollection services)
  4. {
  5. }
  6.  
  7. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  8. {
  9. // JsConfig.DateHandler = DateHandler.ISO8601;
  10. // 保证时间类型的字段可以解析成js识别的时间类型
  11. JsConfig<DateTime>.SerializeFn = time => new DateTime(time.Ticks, DateTimeKind.Local).ToString("o");
  12. JsConfig<DateTime?>.SerializeFn =
  13. time => time != null ? new DateTime(time.Value.Ticks, DateTimeKind.Local).ToString("o") : null;
  14. JsConfig.DateHandler = DateHandler.ISO8601;
  15.  
  16. app.UseServiceStack(new AppHost());
  17.  
  18. app.Run(context =>
  19. {
  20. context.Response.Redirect("/metadata");
  21. return Task.FromResult();
  22. });
  23. }
  24. }

下面就到核心代码了,在主程序中建立多租户Db工程类,让程序可以自动的根据租户Id访问自己的数据库

  1. public class MultiTenantDbFactory : IDbConnectionFactory
  2. {
  3. private readonly IDbConnectionFactory dbFactory;
  4.  
  5. public MultiTenantDbFactory(IDbConnectionFactory dbFactory)
  6. {
  7. this.dbFactory = dbFactory;
  8. }
  9.  
  10. public IDbConnection OpenDbConnection()
  11. {
  12. var tenantId = RequestContext.Instance.Items["TenantId"] as string;
  13. return OpenTenant(tenantId);
  14. }
  15.  
  16. public IDbConnection OpenTenant(string tenantId = null)
  17. {
  18. return tenantId != null
  19. ? dbFactory.OpenDbConnectionString($"Data Source=.; Initial Catalog={tenantId};User Id={tenantId};Password=t123;pooling=true;")
  20. : dbFactory.OpenDbConnection();
  21. }
  22.  
  23. public IDbConnection CreateDbConnection()
  24. {
  25. return dbFactory.CreateDbConnection();
  26. }
  27. }

AppHost中加入如下代码,GlobalRequestFilters的作用,根据传入的租户Id来选择相应的数据库,如果租户Id为null,系统自动使用TMaster数据库

InitDb的作用就是初始化三个数据库,创建表TenantConfig并插入一条记录。

  1. public override void Configure(Container container)
  2. {
  3. ConigureSqlserver(container);
  4. }
  5.  
  6. private void ConigureSqlserver(Container container)
  7. {
  8. var dbFactory = new OrmLiteConnectionFactory(
  9. "Data Source=.; Initial Catalog=TMaster;User Id=TMaster;Password=t123;pooling=true;", SqlServerDialect.Provider);
  10.  
  11. const int noOfTennants = ;
  12.  
  13. container.Register<IDbConnectionFactory>(c =>new MultiTenantDbFactory(dbFactory));
  14.  
  15. var multiDbFactory = (MultiTenantDbFactory)container.Resolve<IDbConnectionFactory>();
  16.  
  17. using (var db = multiDbFactory.OpenTenant())
  18. InitDb(db, "TMaster", "Masters inc.");
  19.  
  20. for(int i=; i<= noOfTennants; i++)
  21. {
  22. var tenantId = $"T{i}";
  23.  
  24. using (var db = multiDbFactory.OpenTenant(tenantId))
  25. InitDb(db, tenantId, $"ACME {tenantId} inc.");
  26. }
  27.  
  28. GlobalRequestFilters.Add((req, res, dto) =>
  29. {
  30. var forTennant = dto as IForTenant;
  31. if (forTennant != null)
  32. RequestContext.Instance.Items.Add("TenantId", forTennant.TenantId);
  33. });
  34. }
  1. public void InitDb(IDbConnection db, string tenantId, string company)
  2. {
  3. db.DropAndCreateTable<TenantConfig>();
  4. db.Insert(new TenantConfig { Id = tenantId, Company = company });
  5. }

这样核心代码就完成了,我们用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 多租户的实现方案的更多相关文章

  1. 多租户SaaS平台的数据库方案

    1.1 多租户是什么 多租户技术(Multi-TenancyTechnology)又称多重租赁技术:是一种软件架构技术,是实现如何在多用户环境下 (此处的多用户一般是面向企业用户)共用相同的系统或程序 ...

  2. 实现saas多租户方案比较

    看到一篇比较多租户数据隔离方案的文章,总结挺不错.其实大部分内容在我前几年写的文章都有. 文章翻译自: https://blog.arkency.com/comparison-of-approache ...

  3. 数据层的多租户浅谈(SAAS多租户数据库设计)

    在上一篇“浅析多租户在 Java 平台和某些 PaaS 上的实现”中我们谈到了应用层面的多租户架构,涉及到 PaaS.JVM.OS 等,与之相应的是数据层也有多租户的支持. 数据层的多租户综述 多租户 ...

  4. EF Core 实现多租户

    目录 SAAS 和多租户 多租户数据隔离方案 使用 EF Core 简单实现多租户 单数据库实现 多数据库实现 源代码 参考 SAAS 和多租户 SaaS(软件及服务)区别于其他应用程序的主要特征就是 ...

  5. 在 Windows Azure 上设计多租户应用程序

    作者:Suren Machiraju 和 Ralph Squillace 审校:Christian Martinez.James Podgorski.Valery Mizonov 和 Michael ...

  6. [转载]数据层的多租户浅谈(SAAS多租户数据库设计)

    原文:http://www.ibm.com/developerworks/cn/java/j-lo-dataMultitenant/index.html 在上一篇“浅析多租户在 Java 平台和某些 ...

  7. 一种Django多租户解决方案

    什么是多租户? 多租户技术或称多重租赁技术,简称SaaS,是一种软件架构技术,是实现如何在多用户环境下(此处的多用户一般是面向企业用户)共用相同的系统或程序组件,并且可确保各用户间数据的隔离性. 多租 ...

  8. 如何在多模型的情况下进行EF6的结构迁移

    所谓多模型就是在一个数据库中包含两个不同模型,或者换句话说就是两个不同DbContext的数据都放到同一个数据库中.这里的多模型不是指多租户的数据库(有谁知道EF很好处理多租户数据库的方案,可以联系我 ...

  9. DAL – RDBMS 的分区

    编辑人员注释:本文章由AzureCAT 云与企业工程组的高级项目经理Shaun Tinline-Jones 和Chris Clayton 共同撰写. "云服务基础"应用程序也称作& ...

随机推荐

  1. sqli-labs:17,增删改

    增 insert into users values(','lcamry','lcamry'); 删 delete from users where id=16 删数据库:drop database ...

  2. 爬虫初窥day2:正则

    正则在线测试 http://tool.oschina.net/regex https://www.regexpal.com/ http://tool.chinaz.com/regex exp1:筛选所 ...

  3. IOS初级:app的图标

    1,首先准备6张png图,分辨率一定要正确,不然报错(The app icon set named "AppIcon" did not have any applicable co ...

  4. java script入门之知识

    1.注释 /*              */ 多行 //单行 2.常见形式 <!DOCTYPE html><html><head><title>My ...

  5. OneZero第三周第四次站立会议(2016.4.7)

    1. 时间: 18:35--18:50 共计15分钟. 2. 成员: X 夏一鸣 * 组长 (博客:http://www.cnblogs.com/xiaym896/), G 郭又铭 (博客:http: ...

  6. idea下使用lombok

    转载 https://blog.csdn.net/u013177446/article/details/53943365 (1)pom引入依赖 <dependency> <group ...

  7. XML 解析的两种方法

    申请博客有一段时间了,一直没有写些什么,今天写一下被遗忘的 xml,因为 ios 现在一般都用 JSON,但毕竟还有一部分老一些的服务器还会有 xml xml 格式的解析方式有两种 1.SAX解析: ...

  8. thymeleaf使用基础教程

    thymeleaf 是新一代的模板引擎,在spring4.0中推荐使用thymeleaf来做前端模版引擎. thymeleaf介绍 简单说, Thymeleaf 是一个跟 Velocity.FreeM ...

  9. 2018.11.06 bzoj1093: [ZJOI2007]最大半连通子图(缩点+拓扑排序)

    传送门 先将原图缩点,缩掉之后的点权就是连通块大小. 然后用拓扑排序统计最长链数就行了. 自己yyyyyy了一下一个好一点的统计方法. 把所有缩了之后的点都连向一个虚点. 然后再跑拓扑,这样最后虚点的 ...

  10. poj--2299(树状数组+离散化)

    一.离散化: https://www.cnblogs.com/2018zxy/p/10104393.html 二.逆序数 AC代码: #include<iostream> #include ...