项目

SaaS 模块 (专业版)

你必须拥有 ABP 团队或更高级别的许可证 才能使用此模块。

该模块用于在多租户应用中管理你的租户和版本;

  • 管理系统中的租户版本。一个租户允许拥有一个版本
  • 设置租户的功能
  • 设置租户的连接字符串
  • 设置版本和租户的功能

有关模块功能的概述,请参阅模块描述页面

如何安装

SaaS 已预装在 启动模板 中。因此,无需手动安装。

此模块遵循 模块开发最佳实践指南,由多个 NuGet 和 NPM 包组成。如果你想了解这些包及其相互关系,请参阅该指南。

你可以访问 SaaS 模块包列表页面 查看与此模块相关的包列表。

租户-版本订阅

SaaS 模块使用支付模块实现了租户对版本的订阅功能。要启用此功能,项目必须包含 Volo.SaasVolo.Payment 模块,并且必须如下所示配置这些模块。

配置

首先,必须正确配置支付模块:

  • 安装 Volo.Payment 模块。

    abp add-module Volo.Payment
    

    或者你也可以通过 ABP Suite 安装。

  • 配置 SaaS 模块以使用支付功能。

    Configure<AbpSaasPaymentOptions>(options =>
    {
        options.IsPaymentSupported = true;
    });
    
  • 遵循支付模块文档中的订阅部分。完成启用 Webhooks配置计划部分。

  • 运行应用程序并转到 Web 应用菜单中的 Saas > Editions 页面。

  • 创建或编辑一个现有版本。如果前面的步骤操作正确,计划下拉菜单应该是可见的。为版本选择一个计划。

使用方法

SaaS 模块不包含一个面向公众的列表页面,用于列出新客户/租户可以订阅的版本。首先,你需要在你的应用中创建这样一个页面。然后,当新客户/租户选择了其中一个版本时,你可以创建一个订阅并将用户重定向到支付模块,如下所示。

  • 注入 ISubscriptionAppService 来为版本创建订阅:
   public class IndexModel : PageModel
   {
          protected ISubscriptionAppService SubscriptionAppService { get; }

          protected ICurrentTenant CurrentTenant { get; }

          public IndexModel(
              ISubscriptionAppService subscriptionAppService,
              ICurrentTenant currentTenant)
          {
              SubscriptionAppService = subscriptionAppService;
              CurrentTenant = currentTenant;
          }

          public async Task<IActionResult> OnPostAsync(Guid editionId)
          {
              var paymentRequest = await SubscriptionAppService.CreateSubscriptionAsync(editionId, CurrentTenant.GetId());

              return LocalRedirectPreserveMethod("/Payment/GatewaySelection?paymentRequestId=" + paymentRequest.Id);
          }
      }

当支付成功完成后,租户和版本的关系将根据订阅状态进行更新。确保支付网关的 Web Hooks 已正确配置。

最后,如果 支付配置 中配置了 callbackUrl 并带有 paymentRequestId 参数,支付模块将把用户重定向到该回调 URL。在此页面,你可以检查支付请求的状态,并在支付状态确认时向用户显示成功消息。由于支付确认是异步的,你需要反复检查支付状态,直到确认。

用户界面

菜单项

SaaS 模块在“主”菜单的“管理”菜单项下添加以下项目:

  • 租户:租户管理页面。
  • 版本:版本管理页面。

SaasHostMenuNamesSaasTenantMenuNames 类包含了这些菜单项名称的常量。

页面

租户管理

租户页面用于管理系统中的租户。

saas-module-tenants-page

你可以在此页面创建新租户或编辑租户:

saas-module-tenant-edit-modal

连接字符串

如果你希望为特定租户使用单独的数据库,可以管理该租户的连接字符串。如果你希望某个租户使用宿主数据库,请选择“使用共享数据库”选项。

saas-module-tenant-connection-strings-modal

模块特定连接字符串

你也可以使用模块特定的数据库连接字符串功能。

要使用此功能,你应该在模块类的 ConfigureServices 方法中配置模块特定的数据库。例如,以下代码配置 Saas 模块为每个租户使用单独的数据库。

Configure<AbpDbConnectionOptions>(options =>
{
    options.Databases.Configure("Saas", database =>
    {
        database.IsUsedByTenants = true;
    });
});

你应该选择“使用模块特定的数据库连接字符串”选项,然后可以确定你的模块及其连接字符串。添加前,可以通过点击“检查”来测试连接。

saas-module-tenant-module-specific-connection-strings-modal

租户功能

你可以设置租户的功能。

saas-module-features-modal

版本管理

版本页面用于管理系统中的版本。

saas-module-editions-page

你可以在此页面创建新版本或编辑现有版本:

saas-module-edition-edit-modal

版本功能

你可以在此页面设置版本的功能:

saas-module-features-modal

数据种子

当你运行 .DbMigrator 应用程序时,此模块会向数据库添加一些初始数据(参见数据种子系统):

  • 创建一个 Standard 版本。

内部结构

领域层

聚合根

此模块遵循实体最佳实践与约定指南。

租户

租户通常代表共享对软件实例的特定权限访问的一组用户。

  • Tenant(聚合根):代表系统中的租户。
    • TenantConnectionString(集合):租户的连接字符串。
版本

版本通常是应用程序功能的一个类别。

  • Edition(聚合根):代表系统中的版本。

仓储

此模块遵循仓储最佳实践与约定指南。

为此模块定义了以下自定义仓储:

  • ITenantRepository
  • IEditionRepository

领域服务

此模块遵循领域服务最佳实践与约定指南。

租户管理器

TenantManager 用于创建租户、更改和验证租户名称。

应用层

应用服务

  • TenantAppService(实现 ITenantAppService):实现租户管理 UI 的用例。
  • EditionAppService(实现 IEditionAppService):实现版本管理 UI 的用例。
  • SubscriptionAppService(实现 ISubscriptionAppService):实现租户-版本订阅的用例。

数据库提供程序

通用

表/集合前缀和架构

默认情况下,所有表/集合都使用 Saas 前缀。如果需要更改表前缀或设置架构名称(如果你的数据库提供程序支持),请在 SaasDbProperties 类上设置静态属性。

连接字符串

此模块使用 Saas 作为连接字符串名称。如果你未定义具有此名称的连接字符串,它将回退到 Default 连接字符串。

详情请参阅连接字符串文档。

Entity Framework Core

  • SaasTenants
    • SaasTenantConnectionStrings
  • SaasEditions

MongoDB

集合
  • SaasTenants
  • SaasEditions

权限

有关为此模块定义的所有权限,请参阅 SaasHostPermissions 类的成员。

Angular UI

安装

为了配置应用程序以使用 SaaS 模块,首先需要从 @volo/abp.ng.saas/config 导入 provideSaasConfig 到根模块。然后,需要将其附加到 appConfig 数组中。

// app.config.ts
import { provideSaasConfig } from '@volo/abp.ng.saas/config';

export const appConfig: ApplicationConfig = {
  providers: [
    // ...
    provideSaasConfig(),
  ],
};

SaaS 模块应该被导入并在你的路由配置中进行懒加载。它有一个静态的 createRoutes 方法用于配置。可用选项如下所示。可以从 @volo/abp.ng.saas 导入。

// app.routes.ts
const APP_ROUTES: Routes = [
  // ...
  {
    path: 'saas',
    loadChildren: () =>
      import('@volo/abp.ng.saas').then(c => c.createRoutes(/* 此处填写选项 */)),
  },
];

如果你是通过启动模板生成的项目,则无需执行任何操作,因为它已经实现了这两种配置。

选项

你可以通过将以下选项传递给 createRoutes 静态方法来修改模块页面的外观和行为:

服务 / 模型

SaaS 模块的服务和模型通过 ABP CLIgenerate-proxy 命令生成。如果你需要该模块的代理,可以在 Angular 项目目录中运行以下命令:

abp generate-proxy --module saas

可替换组件

eSaasComponents 枚举提供了所有可替换组件的键。可以从 @volo/abp.ng.saas 导入。

详情请查看组件替换文档

远程端点 URL

SaaS 模块的远程端点 URL 可以在环境文件中配置。

export const environment = {
  // 其他配置
  apis: {
    default: {
      url: '默认 URL 在此',
    },
    SaasHost: {
      url: 'SaasHost 远程 URL 在此'
    },
    SaasTenant: {
      url: 'SaasTenant 远程 URL 在此'
    },
    // 其他 API 配置
  },
};

上面显示的 SaaS 模块远程 URL 配置是可选的。如果你不设置任何 URL,将使用 default.url 作为回退。

分布式事件

此模块定义了以下 ETO(事件传输对象),允许你订阅模块实体的更改;

  • TenantEto 在对 Tenant 实体进行更改时发布。
  • EditionEto 在对 Edition 实体进行更改时发布。

示例:当新租户创建时获得通知

public class MyHandler :
    IDistributedEventHandler<EntityCreatedEto<TenantEto>>,
    ITransientDependency
{
    public async Task HandleEventAsync(EntityCreatedEto<TenantEto> eventData)
    {
        TenantEto tenant = eventData.Entity;
        // TODO: ...
    }
}

TenantEtoEditionEto 被配置为自动发布事件。其他事件你需要自行配置。请参阅分布式事件总线文档以了解预定义事件的详细信息。

订阅分布式事件在分布式场景(如微服务架构)中特别有用。如果你正在构建单体应用程序,或者在运行租户管理模块的同一进程中监听事件,那么订阅本地事件可能更高效、更容易。

在本文档中