设为首页 加入收藏

TOP

ServiceStack 多租户的实现方案(一)
2019-09-17 18:58:17 】 浏览:49
Tags: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(0);
            });
        }
    }

 

下面就到核心代码了,在主程序中建立多租户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(Contai
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【C#】【对象转XML】xml序列化 下一篇winform判断一个事件是否已经绑定..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目