维基百科中是这样多租户的:

    Volo.Abp.MultiTenancy”multi-tenancy ready”,使用包管理器控制台(PMC)将它安装到你的项目中:

    然后你可以添加 AbpMultiTenancyModule 依赖到你的模块:

    1. using Volo.Abp.MultiTenancy;
    2. namespace MyCompany.MyProject
    3. {
    4. [DependsOn(typeof(AbpMultiTenancyModule))]
    5. public class MyModule : AbpModule
    6. {
    7. //...
    8. }
    9. }

    定义实体

    你可以在你的实体中实现 IMultiTenant 接口来实现多租户,例如:

    1. using System;
    2. using Volo.Abp.Domain.Entities;
    3. using Volo.Abp.MultiTenancy;
    4. namespace MyCompany.MyProject
    5. {
    6. public class Product : AggregateRoot, IMultiTenant
    7. {
    8. public Guid? TenantId { get; set; } //IMultiTenant 定义了 TenantId 属性
    9. public string Name { get; set; }
    10. public float Price { get; set; }
    11. }
    12. }

    实现IMultiTenant接口,需要在实体中定义一个 TenantId 的属性(查看更多有关实体的文档)

    获取当前租户的Id

    你的代码中可能需要获取当前租户的Id(先不管它具体是怎么取得的).对于这种情况你可以并使用 ICurrentTenant 接口.例如:

    1. using Volo.Abp.DependencyInjection;
    2. using Volo.Abp.MultiTenancy;
    3. namespace MyCompany.MyProject
    4. {
    5. public class MyService : ITransientDependency
    6. {
    7. private readonly ICurrentTenant _currentTenant;
    8. public MyService(ICurrentTenant currentTenant)
    9. {
    10. _currentTenant = currentTenant;
    11. }
    12. public void DoIt()
    13. {
    14. var tenantId = _currentTenant.Id;
    15. //在你的代码中使用tenantId
    16. }
    17. }
    18. }

    改变当前租户

    TODO: …

    确定当前租户

    Volo.Abp.AspNetCore.MultiTenancy已经实现了从当前Web请求(从子域名,请求头,cookie,路由…等)中确定当前租户.本文后面会介绍Volo.Abp.AspNetCore.MultiTenancy.

    自定义租户解析器

    你可以像下面这样,在你模块的ConfigureServices方法中将自定义解析器并添加到 AbpTenantResolveOptions中:

    1. using Volo.Abp.Modularity;
    2. using Volo.Abp.MultiTenancy;
    3. namespace MyCompany.MyProject
    4. {
    5. [DependsOn(typeof(AbpMultiTenancyModule))]
    6. public class MyModule : AbpModule
    7. {
    8. public override void ConfigureServices(ServiceConfigurationContext context)
    9. {
    10. {
    11. options.TenantResolvers.Add(new MyCustomTenantResolveContributor());
    12. });
    13. //...
    14. }
    15. }
    16. }

    MyCustomTenantResolveContributor必须像下面这样实现ITenantResolveContributor接口:

    如果能确定租户id或租户名字可以在租户解析器中设置 TenantIdOrName.如果不能确定,那就空着让下一个解析器来确定它.

    租户存储

    Volo.Abp.MultiTenancy中定义了 ITenantStore 从框架中抽象数据源.你可以实现ITenantStore,让它跟任何存储你租户的数据源(例如关系型数据库)一起工作.

    配置数据存储

    有一个内置的(默认的)租户存储,叫ConfigurationTenantStore.它可以被用于存储租户,通过标准的配置系统(使用).因此,你可以通过硬编码或者在appsettings.json文件中定义租户.

    例子:硬编码定义租户
    1. using System;
    2. using Microsoft.Extensions.DependencyInjection;
    3. using Volo.Abp.Data;
    4. using Volo.Abp.Modularity;
    5. using Volo.Abp.MultiTenancy;
    6. namespace MyCompany.MyProject
    7. {
    8. [DependsOn(typeof(AbpMultiTenancyModule))]
    9. public class MyModule : AbpModule
    10. {
    11. public override void ConfigureServices(ServiceConfigurationContext context)
    12. {
    13. Configure<AbpDefaultTenantStoreOptions>(options =>
    14. {
    15. options.Tenants = new[]
    16. {
    17. new TenantConfiguration(
    18. Guid.Parse("446a5211-3d72-4339-9adc-845151f8ada0"), //Id
    19. "tenant1" //Name
    20. ),
    21. new TenantConfiguration(
    22. Guid.Parse("25388015-ef1c-4355-9c18-f6b6ddbaf89d"), //Id
    23. "tenant2" //Name
    24. )
    25. {
    26. //tenant2 有单独的数据库连接字符串
    27. ConnectionStrings =
    28. {
    29. {ConnectionStrings.DefaultConnectionStringName, "..."}
    30. }
    31. }
    32. };
    33. });
    34. }
    35. }
    36. }
    例子:appsettings.json定义租户

    首先从appsetting.json文件中创建你的配置.

    1. using System.IO;
    2. using Microsoft.Extensions.Configuration;
    3. using Microsoft.Extensions.DependencyInjection;
    4. using Volo.Abp.Modularity;
    5. using Volo.Abp.MultiTenancy;
    6. namespace MyCompany.MyProject
    7. {
    8. [DependsOn(typeof(AbpMultiTenancyModule))]
    9. public class MyModule : AbpModule
    10. {
    11. var configuration = BuildConfiguration();
    12. Configure<AbpDefaultTenantStoreOptions>(configuration);
    13. }
    14. private static IConfigurationRoot BuildConfiguration()
    15. {
    16. return new ConfigurationBuilder()
    17. .SetBasePath(Directory.GetCurrentDirectory())
    18. .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    19. .Build();
    20. }
    21. }
    22. }

    然后在appsettings.json中添加 “Tenants“ 节点:

    1. "Tenants": [
    2. {
    3. "Id": "446a5211-3d72-4339-9adc-845151f8ada0",
    4. "Name": "tenant1"
    5. },
    6. {
    7. "Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d",
    8. "Name": "tenant2",
    9. "ConnectionStrings": {
    10. "Default": "...write tenant2's db connection string here..."
    11. }
    12. }
    13. ]
    Volo.Abp… Package (TODO)

    TODO: This package implements ITenantStore using a real database…

    租户信息

    ITenantStore跟 TenantConfiguration类一起工作,并且包含了几个租户属性:

    • Id:租户的唯一Id.
    • Name: 租户的唯一名称.
    • ConnectionStrings:如果这个租户有专门的数据库来存储数据.它可以提供数据库的字符串(它可以具有默认的连接字符串和每个模块的连接字符串).

    代码中改变租户

    TODO…

    Volo.Abp.AspNetCore.MultiTenancy

    Volo.Abp.AspNetCore.MultiTenancy将多租户整合到了ASP.NET Core的程序中.在PMC中使用下面的代码将它安装到项目中.

    1. Install-Package Volo.Abp.AspNetCore.MultiTenancy

    然后添加 AbpAspNetCoreMultiTenancyModule 依赖到你的模块:

    多租户中间件

    Volo.Abp.AspNetCore.MultiTenancy包含了多租户中间件…

    1. app.UseMultiTenancy();

    TODO:…

    从Web请求中确定当前租户

    Volo.Abp.AspNetCore.MultiTenancy 添加了下面这些租户解析器,从当前Web请求(按优先级排序)中确定当前租户.

    • CurrentUserTenantResolveContributor: 如果当前用户已登录,从当前用户的声明中获取租户Id. 出于安全考虑,应该始终将其做为第一个Contributor.
    • QueryStringTenantResolveContributor: 尝试从query string参数中获取当前租户,默认参数名为”__tenant”.
    • FormTenantResolveContributor: 尝试从form参数中获取当前租户,默认参数名为”__tenant”.
    • RouteTenantResolveContributor:尝试从当前路由中获取(URL路径),默认是变量名是”__tenant”.所以,如果你的路由中定义了这个变量,就可以从路由中确定当前租户.
    • HeaderTenantResolveContributor: 尝试从HTTP header中获取当前租户,默认的header名称是”__tenant”.
    • CookieTenantResolveContributor: 尝试从当前cookie中获取当前租户.默认的Cookie名称是”__tenant”.

    可以使用AbpAspNetCoreMultiTenancyOptions修改默认的参数名”__tenant”.例如:

    1. services.Configure<AbpAspNetCoreMultiTenancyOptions>(options =>
    2. {
    3. options.TenantKey = "MyTenantKey";
    4. });
    域名租户解析器

    实际项目中,大多数情况下你想通过子域名(如mytenant1.mydomain.com)或全域名(如mytenant.com)中确定当前租户.如果是这样,你可以配置AbpTenantResolveOptions添加一个域名租户解析器.

    例子:添加子域名解析器
    1. using Microsoft.Extensions.DependencyInjection;
    2. using Volo.Abp.AspNetCore.MultiTenancy;
    3. using Volo.Abp.Modularity;
    4. using Volo.Abp.MultiTenancy;
    5. namespace MyCompany.MyProject
    6. {
    7. [DependsOn(typeof(AbpAspNetCoreMultiTenancyModule))]
    8. public class MyModule : AbpModule
    9. {
    10. public override void ConfigureServices(ServiceConfigurationContext context)
    11. {
    12. Configure<AbpTenantResolveOptions>(options =>
    13. {
    14. //子域名格式: {0}.mydomain.com (作为第二优先级解析器添加, 位于CurrentUserTenantResolveContributor之后)
    15. options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com"));
    16. });
    17. //...
    18. }
    19. }
    20. }

    {0}是用来确定当前租户唯一名称的占位符.

      例子:添加全域名解析器