ThTenantProvisioningAppService.cs 3.32 KB
using FoodLabeling.Th.Application.Contracts.Dtos.MultiTenancy;
using FoodLabeling.Th.Application.Contracts.IServices;
using FoodLabeling.Th.Application.Contracts.Options;
using FoodLabeling.Th.Application.MultiTenancy;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.MultiTenancy;
using Yi.Framework.TenantManagement.Application.Contracts;
using Yi.Framework.TenantManagement.Application.Contracts.Dtos;

namespace FoodLabeling.Th.Application.Services;

/// <summary>
/// 泰额版租户独立库开通(平台主库 yitenant + 租户业务库)
/// </summary>
[Authorize]
public class ThTenantProvisioningAppService : ApplicationService, IThTenantProvisioningAppService
{
    private readonly ITenantService _tenantService;
    private readonly FoodLabelingThTenantDatabaseOptions _dbOptions;

    public ThTenantProvisioningAppService(
        ITenantService tenantService,
        IOptions<FoodLabelingThTenantDatabaseOptions> dbOptions)
    {
        _tenantService = tenantService;
        _dbOptions = dbOptions.Value;
    }

    /// <inheritdoc />
    public virtual async Task<ThProvisionTenantOutputDto> ProvisionAsync(ThProvisionTenantInputVo input)
    {
        if (string.IsNullOrWhiteSpace(input.Name))
        {
            throw new UserFriendlyException("租户名称不能为空");
        }

        var connectionString = string.IsNullOrWhiteSpace(input.TenantConnectionString)
            ? TenantDatabaseConnectionStringBuilder.BuildMySqlConnectionString(_dbOptions, input.Name)
            : input.TenantConnectionString.Trim();

        var databaseName = ExtractDatabaseName(connectionString)
                           ?? TenantDatabaseConnectionStringBuilder.BuildDatabaseName(_dbOptions, input.Name);

        // 平台主库写入 yitenant(CurrentTenant 为空时走 DbConnOptions 主库)
        var dbType = Enum.IsDefined(typeof(DbType), input.DbType)
            ? (DbType)input.DbType
            : DbType.MySql;

        var created = await _tenantService.CreateAsync(new TenantCreateInput
        {
            Name = input.Name.Trim(),
            TenantConnectionString = connectionString,
            DbType = dbType
        });

        var initialized = false;
        if (input.InitializeDatabase)
        {
            await _tenantService.InitAsync(created.Id);
            initialized = true;
        }

        return new ThProvisionTenantOutputDto
        {
            TenantId = created.Id,
            Name = created.Name,
            DatabaseName = databaseName,
            TenantConnectionString = connectionString,
            DatabaseInitialized = initialized
        };
    }

    /// <inheritdoc />
    public virtual Task InitializeTenantDatabaseAsync(Guid tenantId)
    {
        return _tenantService.InitAsync(tenantId);
    }

    private static string? ExtractDatabaseName(string connectionString)
    {
        const string key = "database=";
        var idx = connectionString.IndexOf(key, StringComparison.OrdinalIgnoreCase);
        if (idx < 0)
        {
            return null;
        }

        var start = idx + key.Length;
        var end = connectionString.IndexOf(';', start);
        return end < 0
            ? connectionString[start..].Trim()
            : connectionString[start..end].Trim();
    }
}