|
|
@ -1,152 +1,162 @@
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
using Volo.Abp;
|
|
|
|
using Volo.Abp.Data;
|
|
|
|
using Volo.Abp.Data;
|
|
|
|
using Volo.Abp.DependencyInjection;
|
|
|
|
using Volo.Abp.DependencyInjection;
|
|
|
|
using Volo.Abp.MultiTenancy;
|
|
|
|
using Volo.Abp.MultiTenancy;
|
|
|
|
|
|
|
|
|
|
|
|
namespace NPin.Framework.TenantManagement.Domain;
|
|
|
|
namespace NPin.Framework.TenantManagement.Domain;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// 数据库连接字符串解析器,替代原有
|
|
|
|
/// 数据库连接字符串解析器,替代原有
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
[Dependency(ReplaceServices = true)]
|
|
|
|
[Dependency(ReplaceServices = true)]
|
|
|
|
public class NPinMultiTenantConnectionStringResolver : DefaultConnectionStringResolver
|
|
|
|
public class NPinMultiTenantConnectionStringResolver : DefaultConnectionStringResolver
|
|
|
|
{
|
|
|
|
{
|
|
|
|
private readonly ICurrentTenant _currentTenant;
|
|
|
|
private readonly ICurrentTenant _currentTenant;
|
|
|
|
private readonly IServiceProvider _serviceProvider;
|
|
|
|
private readonly IServiceProvider _serviceProvider;
|
|
|
|
|
|
|
|
|
|
|
|
public NPinMultiTenantConnectionStringResolver(IOptionsMonitor<AbpDbConnectionOptions> options,
|
|
|
|
public NPinMultiTenantConnectionStringResolver(IOptionsMonitor<AbpDbConnectionOptions> options,
|
|
|
|
ICurrentTenant currentTenant, IServiceProvider serviceProvider) : base(options)
|
|
|
|
ICurrentTenant currentTenant, IServiceProvider serviceProvider) : base(options)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_currentTenant = currentTenant;
|
|
|
|
_currentTenant = currentTenant;
|
|
|
|
_serviceProvider = serviceProvider;
|
|
|
|
_serviceProvider = serviceProvider;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override async Task<string> ResolveAsync(string? connectionStringName = null)
|
|
|
|
public override async Task<string> ResolveAsync(string? connectionStringName = null)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (_currentTenant.Id == null)
|
|
|
|
if (_currentTenant.Id == null)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 无租户信息,使用原有解析器
|
|
|
|
// 无租户信息,使用原有解析器
|
|
|
|
return await base.ResolveAsync(connectionStringName);
|
|
|
|
return await base.ResolveAsync(connectionStringName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通过Store寻找租户缓存
|
|
|
|
// 通过Store寻找租户缓存
|
|
|
|
var tenant = await FindTenantConfigurationAsync(_currentTenant.Id.Value);
|
|
|
|
var tenant = await FindTenantConfigurationAsync(_currentTenant.Id.Value);
|
|
|
|
if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty())
|
|
|
|
if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 找不到租户缓存,使用原有解析器
|
|
|
|
// 找不到租户缓存,使用原有解析器
|
|
|
|
return await base.ResolveAsync(connectionStringName);
|
|
|
|
return await base.ResolveAsync(connectionStringName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default;
|
|
|
|
var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default;
|
|
|
|
// Requesting default connection string...
|
|
|
|
|
|
|
|
if (connectionStringName == null ||
|
|
|
|
var connString = tenant.ConnectionStrings?.FirstOrDefault().Value;
|
|
|
|
connectionStringName == ConnectionStrings.DefaultConnectionStringName)
|
|
|
|
if (!connString.IsNullOrWhiteSpace())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Return tenant's default or global default
|
|
|
|
return connString;
|
|
|
|
return !tenantDefaultConnectionString.IsNullOrWhiteSpace()
|
|
|
|
}
|
|
|
|
? tenantDefaultConnectionString!
|
|
|
|
|
|
|
|
: Options.ConnectionStrings.Default!;
|
|
|
|
// 库隔离
|
|
|
|
}
|
|
|
|
var database = Options.Databases.GetMappedDatabaseOrNull(connectionStringName);
|
|
|
|
|
|
|
|
if (database is { IsUsedByTenants: true })
|
|
|
|
// Requesting specific connection string...
|
|
|
|
{
|
|
|
|
var connString = tenant.ConnectionStrings?.FirstOrDefault().Value;
|
|
|
|
connString = tenant.ConnectionStrings?.GetOrDefault(database.DatabaseName);
|
|
|
|
if (!connString.IsNullOrWhiteSpace())
|
|
|
|
if (!connString.IsNullOrWhiteSpace())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Found for the tenant
|
|
|
|
return connString;
|
|
|
|
return connString!;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 库隔离
|
|
|
|
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
|
|
|
|
var database = Options.Databases.GetMappedDatabaseOrNull(connectionStringName);
|
|
|
|
{
|
|
|
|
if (database is { IsUsedByTenants: true })
|
|
|
|
return tenantDefaultConnectionString;
|
|
|
|
{
|
|
|
|
}
|
|
|
|
connString = tenant.ConnectionStrings?.GetOrDefault(database.DatabaseName);
|
|
|
|
|
|
|
|
if (!connString.IsNullOrWhiteSpace())
|
|
|
|
return await base.ResolveAsync(connectionStringName);
|
|
|
|
{
|
|
|
|
}
|
|
|
|
return connString;
|
|
|
|
|
|
|
|
}
|
|
|
|
protected virtual async Task<TenantConfiguration?> FindTenantConfigurationAsync(Guid tenantId)
|
|
|
|
}
|
|
|
|
{
|
|
|
|
|
|
|
|
using var serviceScope = _serviceProvider.CreateScope();
|
|
|
|
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
var tenantStore = serviceScope
|
|
|
|
return tenantDefaultConnectionString;
|
|
|
|
.ServiceProvider
|
|
|
|
}
|
|
|
|
.GetRequiredService<ITenantStore>();
|
|
|
|
|
|
|
|
|
|
|
|
return await base.ResolveAsync(connectionStringName);
|
|
|
|
return await tenantStore.FindAsync(tenantId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<TenantConfiguration?> FindTenantConfigurationAsync(Guid tenantId)
|
|
|
|
[Obsolete("Use ResolveAsync Instead.")]
|
|
|
|
{
|
|
|
|
public override string Resolve(string? connectionStringName = null)
|
|
|
|
using var serviceScope = _serviceProvider.CreateScope();
|
|
|
|
{
|
|
|
|
|
|
|
|
if (_currentTenant.Id == null)
|
|
|
|
var tenantStore = serviceScope
|
|
|
|
{
|
|
|
|
.ServiceProvider
|
|
|
|
// 无租户信息,使用原有解析器
|
|
|
|
.GetRequiredService<ITenantStore>();
|
|
|
|
return base.Resolve(connectionStringName);
|
|
|
|
|
|
|
|
}
|
|
|
|
return await tenantStore.FindAsync(tenantId);
|
|
|
|
|
|
|
|
}
|
|
|
|
// 通过Store寻找租户缓存
|
|
|
|
|
|
|
|
var tenant = FindTenantConfiguration(_currentTenant.Id.Value);
|
|
|
|
[Obsolete("Use ResolveAsync Instead.")]
|
|
|
|
if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty())
|
|
|
|
public override string Resolve(string? connectionStringName = null)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 找不到租户缓存,使用原有解析器
|
|
|
|
if (_currentTenant.Id == null)
|
|
|
|
return base.Resolve(connectionStringName);
|
|
|
|
{
|
|
|
|
}
|
|
|
|
// 无租户信息,使用原有解析器
|
|
|
|
|
|
|
|
return base.Resolve(connectionStringName);
|
|
|
|
var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Requesting default connection string...
|
|
|
|
// 通过Store寻找租户缓存
|
|
|
|
if (connectionStringName == null ||
|
|
|
|
var tenant = FindTenantConfiguration(_currentTenant.Id.Value);
|
|
|
|
connectionStringName == ConnectionStrings.DefaultConnectionStringName)
|
|
|
|
if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//Return tenant's default or global default
|
|
|
|
// 找不到租户缓存,使用原有解析器
|
|
|
|
return !tenantDefaultConnectionString.IsNullOrWhiteSpace()
|
|
|
|
return base.Resolve(connectionStringName);
|
|
|
|
? tenantDefaultConnectionString!
|
|
|
|
}
|
|
|
|
: Options.ConnectionStrings.Default!;
|
|
|
|
|
|
|
|
}
|
|
|
|
var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default;
|
|
|
|
|
|
|
|
|
|
|
|
// Requesting specific connection string...
|
|
|
|
// Requesting default connection string...
|
|
|
|
var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName);
|
|
|
|
if (connectionStringName == null ||
|
|
|
|
if (!connString.IsNullOrWhiteSpace())
|
|
|
|
connectionStringName == ConnectionStrings.DefaultConnectionStringName)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Found for the tenant
|
|
|
|
//Return tenant's default or global default
|
|
|
|
return connString!;
|
|
|
|
return !tenantDefaultConnectionString.IsNullOrWhiteSpace()
|
|
|
|
}
|
|
|
|
? tenantDefaultConnectionString!
|
|
|
|
|
|
|
|
: Options.ConnectionStrings.Default!;
|
|
|
|
// Fallback to tenant's default connection string if available
|
|
|
|
}
|
|
|
|
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
// Requesting specific connection string...
|
|
|
|
return tenantDefaultConnectionString!;
|
|
|
|
var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName);
|
|
|
|
}
|
|
|
|
if (!connString.IsNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
// Try to find the specific connection string for given name
|
|
|
|
// Found for the tenant
|
|
|
|
var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName);
|
|
|
|
return connString!;
|
|
|
|
if (!connStringInOptions.IsNullOrWhiteSpace())
|
|
|
|
}
|
|
|
|
{
|
|
|
|
|
|
|
|
return connStringInOptions!;
|
|
|
|
// Fallback to tenant's default connection string if available
|
|
|
|
}
|
|
|
|
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
// Fallback to the global default connection string
|
|
|
|
return tenantDefaultConnectionString!;
|
|
|
|
var defaultConnectionString = Options.ConnectionStrings.Default;
|
|
|
|
}
|
|
|
|
if (!defaultConnectionString.IsNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
// Try to find the specific connection string for given name
|
|
|
|
return defaultConnectionString!;
|
|
|
|
var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName);
|
|
|
|
}
|
|
|
|
if (!connStringInOptions.IsNullOrWhiteSpace())
|
|
|
|
|
|
|
|
{
|
|
|
|
throw new AbpException("No connection string defined!");
|
|
|
|
return connStringInOptions!;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fallback to the global default connection string
|
|
|
|
[Obsolete("Use FindTenantConfigurationAsync Instead.")]
|
|
|
|
var defaultConnectionString = Options.ConnectionStrings.Default;
|
|
|
|
protected virtual TenantConfiguration? FindTenantConfiguration(Guid tenantId)
|
|
|
|
if (!defaultConnectionString.IsNullOrWhiteSpace())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
using var serviceScope = _serviceProvider.CreateScope();
|
|
|
|
return defaultConnectionString!;
|
|
|
|
|
|
|
|
}
|
|
|
|
var tenantStore = serviceScope
|
|
|
|
|
|
|
|
.ServiceProvider
|
|
|
|
throw new AbpException("No connection string defined!");
|
|
|
|
.GetRequiredService<ITenantStore>();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tenantStore.Find(tenantId);
|
|
|
|
|
|
|
|
}
|
|
|
|
[Obsolete("Use FindTenantConfigurationAsync Instead.")]
|
|
|
|
|
|
|
|
protected virtual TenantConfiguration? FindTenantConfiguration(Guid tenantId)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using var serviceScope = _serviceProvider.CreateScope();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var tenantStore = serviceScope
|
|
|
|
|
|
|
|
.ServiceProvider
|
|
|
|
|
|
|
|
.GetRequiredService<ITenantStore>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return tenantStore.Find(tenantId);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|