多租户解析与Demo

在做Saas应用时,多租户解析往往是很重要的组成部分,也是用户访问网站最先处理的逻辑。

文前介绍:

多租户的数据库实现方式主要有三种:

  1. 单一数据库实现,每条数据标识租户Id进行识别数据属于哪个租户
  2. 一租户一个数据库,能够做到完全的数据隔离
  3. 混合模式,部分数据在一张表上,主要是一些基础数据;其他业务数据分库存储。

无论是哪种方式都要知道租户是谁才能查询数据库。

获取租户的方式也可以有多种:

  1. 根据域名或者子域名不同可以获知租户,上面的所有场景都适合使用;(必须要有域名和dns服务)
  2. 根据用户id获取租户信息,从而存入前端的cookie中或者header中,只适用于上面的1、3方式,因为需要不同租户的用户都存入一种表中,方便查询对应的租户信息;

下文中的例子只是简单的一个例子,没有进一步的业务场景,实现功能如下:

用户根据不同的域名进入系统;

后台拿刀http传入的域名并解析;

查询租户数据库,查找出租户名称返回显示。

新建解决方案,并其下新增三个项目:

try_MultiTenantApi:webapi项目,项目的启动项目,为了方方便,租户的Service和IService放入了这个项目中,实际应用时要放入业务层;

MultiTenantApi.Models:类库项目,存放租户对象;

MultiTenantApi.Data:数据层,使用efcore,存放上下文DbContext和迁移文件

多租户解析与Demo

MultiTenantApi.Models中新增实体Tenant

```
public class Tenant
{
    public int Id { get; set; }
    public string Identifier { get; set; } // 租户标识符,例如域名
    public string Name { get; set; }
    public string ConnectionString { get; set; } // 每个租户的独立数据库连接字符串
}
```

MultiTenantApi.Data:

引入nuget包:要注意跟你项目的.net版本相同

多租户解析与Demo

这些包的具体说明:

  1. Microsoft.EntityFrameworkCore

    • 功能: Entity Framework Core 是一个现代的对象-关系映射器(ORM),用于 .NET。它支持 LINQ 查询、变更跟踪、更新和模式迁移。EF Core 可以与多种数据库一起工作,包括 SQL Server、Azure SQL Database、SQLite 和 Azure Cosmos DB。
    • 作用: 提供了核心的 ORM 功能,用于在 .NET 应用程序中与数据库进行交互。
    • Microsoft.EntityFrameworkCore.Design

    • 功能: 提供了 Entity Framework Core 工具的共享设计时组件。这些组件包括用于创建和管理迁移的工具。

    • 作用: 用于在设计时(如运行迁移命令时)提供必要的工具支持,帮助开发者更高效地管理和生成数据库迁移。
    • Microsoft.EntityFrameworkCore.Proxies

    • 功能: 为 Entity Framework Core 提供延迟加载代理。这些代理用于在需要时加载相关对象,从而减少内存使用和提高性能。

    • 作用: 通过代理机制实现延迟加载,提高应用程序的性能和响应速度。
    • Microsoft.EntityFrameworkCore.SqlServer

    • 功能: 提供了针对 Microsoft SQL Server 的数据库提供程序。这使得 Entity Framework Core 能够与 SQL Server 数据库进行交互。

    • 作用: 为 SQL Server 数据库提供特定的数据库提供程序,确保 EF Core 能够正确地与 SQL Server 交互。
    • Microsoft.EntityFrameworkCore.Tools

    • 功能: 提供了 Entity Framework Core 工具,用于 NuGet Package Manager Console 中的 Visual Studio。

    • 作用: 通过 Visual Studio 的 NuGet Package Manager Console 提供 EF Core 工具,帮助开发者更方便地管理和使用 EF Core 的设计时工具。

新增数据上下文:

```
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions options)
    : base(options)
    {
    }
    public DbSet Tenants { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity().HasData(
            new Tenant { Id = 1, Identifier = "tenant1", Name = "Tenant 1", ConnectionString = "Server=(localdb)\mssqllocaldb;Database=TenantDb1;Trusted_Connection=True;" },
            new Tenant { Id = 2, Identifier = "tenant2", Name = "Tenant 2", ConnectionString = "Server=(localdb)\mssqllocaldb;Database=TenantDb2;Trusted_Connection=True;" }
        );
    }
}
```

注意实际应用中上面的数据库连接字符串根据你的具体情况变动一下,因为本例子没有用到这个字段所以想要尝试可以不用改。

try_MultiTenantApi:

引入nuget包:

多租户解析与Demo

新建类TenantService:

```
public interface ITenantService
{
    Task GetTenantByIdentifierAsync(string identifier);
}

public class TenantService : ITenantService
{
    private readonly ApplicationDbContext _context;

    public TenantService(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task GetTenantByIdentifierAsync(string identifier)
    {
        return await _context.Tenants.FirstOrDefaultAsync(t => t.Identifier == identifier);
    }
}
```

新建一个中间件TenantMiddleware:

用于每次的请求解析出租户信息

```
namespace try_MultiTenantApi
{
    public class TenantMiddleware
    {
        private readonly RequestDelegate _next;

        public TenantMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context, ITenantService tenantService)
        {
            var subdomain = GetSubdomain(context.Request.Host.Value);
            if (!string.IsNullOrEmpty(subdomain))
            {
                var tenant = await tenantService.GetTenantByIdentifierAsync(subdomain);
                if (tenant != null)
                {
                    context.Items["Tenant"] = tenant;
                }
            }

            await _next(context);
        }

        private string GetSubdomain(string host)
        {
            var parts = host.Split('.');
            return parts.Length > 2 ? parts[0] : null;
        }
    }
}

public static class TenantMiddlewareExtensions
{
    public static IApplicationBuilder UseTenantMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware();
    }
}
```

配置appsetting文件,配置租户数据库连接字符串:

```
"ConnectionStrings": {
  "DefaultConnection": "Data Source=localhost;Initial Catalog=try_MultiTenant;User ID=sa;Password=******;Encrypt=False;"
},
```

修改Program:

```
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}


app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.UseTenantMiddleware(); // 使用租户解析中间件
app.MapControllers();

app.Run();
```

新建一个controller:ValuesController

```
[ApiController]
[Route("[controller]")]
public class ValuesController : ControllerBase
{
    private readonly ITenantService _tenantService;

    public ValuesController(ITenantService tenantService)
    {
        _tenantService = tenantService;
    }

    [HttpGet(nameof(Get1))]
    public async Task Get1()
    {
        var tenant = HttpContext.Items["Tenant"] as Tenant;
        if (tenant == null)
        {
            return NotFound("Tenant not found");
        }

        return Ok(new { Message = $"Hello from {tenant.Name}" });
    }
}
```

OK,至此项目就编码完成,接下来就是进行数据迁移。因为前面上下文中已经设置了出事测试数据

add-migration init

update-database

到此,租户的数据库已经创建,并且也有了初始的测试数据:

多租户解析与Demo

为了测试方便咱们在launch启动文件中配置两个租户的访问地址:

```
"profiles": {
  "http": {
    "commandName": "Project",
    "dotnetRunMessages": true,
    "launchBrowser": true,
    "launchUrl": "swagger",
    "applicationUrl": "http://localhost:5252;http://tenant1.Paas.JBWL.com:5252",
    "environmentVariables": {
      "ASPNETCORE_ENVIRONMENT": "Development"
    }
  },
}
```

接下来设置try_MultiTenantApi项目为启动项目,启来后出swagger页面:

多租户解析与Demo

页面地址是默认第一个http://localhost:5252/

下面我们就可以修改一下本地的host文件映射两个域名,可以使用swichhost,也可以找到本地的host文件,增加地址映射

```
127.0.0.1 tenant1.Paas.JBWL.com
127.0.0.1 tenant2.Paas.JBWL.com
```

启用后访问

```
tenant1.Paas.JBWL.com:5252
```

出现前面一模一样的页面,访问一下测试接口看是否解析成功:

多租户解析与Demo

成功!

接下来试一下tenant2.paas.jbwl.com:5252

多租户解析与Demo

至此,这个测试demo也就完成了,只要解析出租户信息,接下来Saas的租户数据就能获取了。

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/5363.html

(0)
LomuLomu
上一篇 2025 年 1 月 6 日 上午11:39
下一篇 2025 年 1 月 6 日 下午12:40

相关推荐

  • JAVA 图形界面编程 AWT篇(1)

    前言 为了应对JAVA课设,小编走上了java的图形界面编程的道路,通过博客分享自己的学习历程,并进行笔记的记录。 AWT(Abstract Window Toolkit)介绍 AWT(抽象窗口工具包)是 Java 最早的图形用户界面(GUI)框架之一,主要用于构建桌面应用程序的图形界面。最初在 JDK 1.0 版本中作为 Java GUI 的核心库引入,旨…

    未分类 2024 年 12 月 30 日
    28100
  • Postman安装及汉化操作全解(含图文步骤)

    前言 Postman 是一款功能强大的 API 测试工具,深受开发者喜爱。然而,原版 Postman 是英文界面,对于习惯中文的用户可能不够友好。本教程详细介绍如何下载安装 Postman 并成功实现汉化,适合零基础用户。 一、下载安装包 首先,获取 Postman 的安装包及对应汉化包:👉 点击获取 Postman 安装及汉化包 ⚠️ 注意事项: 1. P…

    2025 年 1 月 6 日
    32800
  • Java【多线程】(1)进程与线程

    “`markdown 目录 1. 前言 2. 正文 2.1 什么是进程 2.2 PCB(进程控制块) 2.2.1 进程id 2.2.2 内存指针 2.2.3 文件描述符表 2.2.4 进程状态 2.2.4.1 就绪状态 2.2.4.2 阻塞状态 2.2.5 进程优先级 2.2.6 进程上下文 2.2.7 进程的记账信息 2.3 CPU操作进程的方法 2.4…

    2024 年 12 月 28 日
    28200
  • 数据库连接池优化:从金融业务到编程实践的高效转换

    title: 数据库连接池优化:从金融业务到编程实践的高效转换date: 2025/05/08 01:52:52updated: 2025/05/08 01:52:52author: devmaster excerpt:在FastAPI框架下,通过合理配置Tortoise-ORM的连接池参数(如最大容量、超时设置和连接回收机制),可显著提升系统响应速度。结合…

    2025 年 5 月 11 日
    7100
  • manim边做边学–动画联动

    今天介绍Manim中的动画联动的技巧,在数学动画中,动画联动是常用的功能, 比如讲解平面几何中三角形与圆的位置关系变化,通过动画联动可以让圆沿着三角形的边滚动,或者让三角形的顶点在圆上移动,从而直观地展示内切、外接等几何关系。 总之,通过动画联动,可以将复杂的概念、关系或变化过程以动态的方式展示出来。 这种动态展示比静态的图像或文字描述更具吸引力,能让观众更…

    2025 年 1 月 16 日
    29400

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信