diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs new file mode 100644 index 000000000..0adf83f11 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Auditing; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.Saas.Tenants; + +public class TenantConnectionStringCheckInput +{ + [Required] + public string Provider { get; set; } + + public string Name { get; set; } + + [Required] + [DisableAuditing] + [DynamicStringLength(typeof(TenantConnectionStringConsts), nameof(TenantConnectionStringConsts.MaxValueLength))] + public string ConnectionString { get; set; } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs new file mode 100644 index 000000000..ba9766ebe --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.Saas.Tenants; + +public class TenantConnectionStringCheckResultDto +{ + public bool Connected { get; set; } + public TenantConnectionStringCheckResultDto() + { + + } + + public TenantConnectionStringCheckResultDto(bool connected) + { + Connected = connected; + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs index db5a30ad1..25575cbec 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs @@ -31,4 +31,6 @@ public interface ITenantAppService : Task DeleteConnectionStringAsync( Guid id, [Required] string connectionName); + + Task CheckConnectionStringAsync(TenantConnectionStringCheckInput input); } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs index 682914293..c3f938279 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs @@ -1,6 +1,7 @@ using LINGYUN.Abp.Saas.Features; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; @@ -20,18 +21,18 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService protected IDistributedEventBus EventBus { get; } protected ITenantRepository TenantRepository { get; } protected ITenantManager TenantManager { get; } - protected IConnectionStringChecker ConnectionStringChecker { get; } + protected AbpSaasConnectionStringCheckOptions ConnectionStringCheckOptions { get; } public TenantAppService( ITenantRepository tenantRepository, ITenantManager tenantManager, IDistributedEventBus eventBus, - IConnectionStringChecker connectionStringChecker) + IOptions connectionStringCheckOptions) { EventBus = eventBus; TenantRepository = tenantRepository; TenantManager = tenantManager; - ConnectionStringChecker = connectionStringChecker; + ConnectionStringCheckOptions = connectionStringCheckOptions.Value; } public async virtual Task GetAsync(Guid id) @@ -85,14 +86,12 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService if (!input.UseSharedDatabase) { - await CheckConnectionString(input.DefaultConnectionString); tenant.SetDefaultConnectionString(input.DefaultConnectionString); if (input.ConnectionStrings.Any()) { foreach (var connectionString in input.ConnectionStrings) { - await CheckConnectionString(connectionString.Value, connectionString.Name); tenant.SetConnectionString(connectionString.Name, connectionString.Value); } } @@ -215,8 +214,6 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService [Authorize(AbpSaasPermissions.Tenants.ManageConnectionStrings)] public async virtual Task SetConnectionStringAsync(Guid id, TenantConnectionStringSetInput input) { - await CheckConnectionString(input.Value, input.Name); - var tenant = await TenantRepository.GetAsync(id); var oldConnectionString = tenant.FindConnectionString(input.Name); @@ -275,33 +272,34 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService await CurrentUnitOfWork.SaveChangesAsync(); } - protected async virtual Task CheckConnectionString(string connectionString, string name = null) + public async virtual Task CheckConnectionStringAsync(TenantConnectionStringCheckInput input) { - try + if (!ConnectionStringCheckOptions.ConnectionStringCheckers.TryGetValue(input.Provider, out var connectionStringChecker)) { - var checkResult = await ConnectionStringChecker.CheckAsync(connectionString); - // 检查连接是否可用 - if (!checkResult.Connected) - { - throw name.IsNullOrWhiteSpace() - ? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString) - : new BusinessException(AbpSaasErrorCodes.InvalidConnectionString) - .WithData("Name", name); - } - // 默认连接字符串改变不能影响到现有数据库 - if (checkResult.DatabaseExists && name.IsNullOrWhiteSpace()) - { - throw new BusinessException(AbpSaasErrorCodes.DefaultConnectionStringDatabaseExists); - } + throw new BusinessException(AbpSaasErrorCodes.ConnectionStringProviderNotSupport) + .WithData("Name", input.Provider); } - catch (Exception e) + + var checkResult = await connectionStringChecker.CheckAsync(input.ConnectionString); + + if (checkResult.Error != null) + { + Logger.LogWarning(checkResult.Error, "An error occurred while checking the database connection."); + } + + // 检查连接是否可用 + if (!checkResult.Connected) { - Logger.LogWarning("An error occurred while checking the validity of the connection string"); - Logger.LogWarning(e.Message); - throw name.IsNullOrWhiteSpace() + throw input.Name.IsNullOrWhiteSpace() ? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString) : new BusinessException(AbpSaasErrorCodes.InvalidConnectionString) - .WithData("Name", name); + .WithData("Name", input.Name); } + // 默认连接字符串改变不能影响到现有数据库 + // 移除此检查, 需要配合数据库迁移才有效 + //if (checkResult.DatabaseExists && (input.Name.IsNullOrWhiteSpace() || "Default".Equals(input.Name, StringComparison.InvariantCultureIgnoreCase))) + //{ + // throw new BusinessException(AbpSaasErrorCodes.DefaultConnectionStringDatabaseExists); + //} } } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj new file mode 100644 index 000000000..fd82b2d2c --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj @@ -0,0 +1,28 @@ + + + + + + + net9.0 + LINGYUN.Abp.Saas.DbChecker + LINGYUN.Abp.Saas.DbChecker + false + false + false + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs new file mode 100644 index 000000000..d080185c3 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs @@ -0,0 +1,24 @@ +using LINGYUN.Abp.Saas.MySql; +using LINGYUN.Abp.Saas.Oracle; +using LINGYUN.Abp.Saas.PostgreSql; +using LINGYUN.Abp.Saas.Sqlite; +using LINGYUN.Abp.Saas.SqlServer; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Saas; + +[DependsOn(typeof(AbpSaasDomainModule))] +public class AbpSaasDbCheckerModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.ConnectionStringCheckers["mysql"] = new MySqlConnectionStringChecker(); + options.ConnectionStringCheckers["oracle"] = new OracleConnectionStringChecker(); + options.ConnectionStringCheckers["postgres"] = new NpgsqlConnectionStringChecker(); + options.ConnectionStringCheckers["sqlite"] = new SqliteConnectionStringChecker(); + options.ConnectionStringCheckers["sqlserver"] = new SqlServerConnectionStringChecker(); + }); + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs new file mode 100644 index 000000000..1fd6d1887 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs @@ -0,0 +1,39 @@ +using LINGYUN.Abp.Saas.Tenants; +using MySqlConnector; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Saas.MySql; + +public class MySqlConnectionStringChecker : IDataBaseConnectionStringChecker +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new MySqlConnectionStringBuilder(connectionString) + { + ConnectionLifeTime = 1 + }; + + var oldDatabaseName = connString.Database; + connString.Database = "mysql"; + + try + { + await using var conn = new MySqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs new file mode 100644 index 000000000..2651598bc --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs @@ -0,0 +1,35 @@ +using LINGYUN.Abp.Saas.Tenants; +using Oracle.ManagedDataAccess.Client; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Saas.Oracle; + +public class OracleConnectionStringChecker : IDataBaseConnectionStringChecker +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new OracleConnectionStringBuilder(connectionString) + { + ConnectionTimeout = 1 + }; + + try + { + await using var conn = new OracleConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs new file mode 100644 index 000000000..89c4cf444 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs @@ -0,0 +1,40 @@ +using LINGYUN.Abp.Saas.Tenants; +using Npgsql; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Saas.PostgreSql; + +public class NpgsqlConnectionStringChecker : IDataBaseConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new NpgsqlConnectionStringBuilder(connectionString) + { + Timeout = 1 + }; + + var oldDatabaseName = connString.Database; + connString.Database = "postgres"; + + try + { + await using var conn = new NpgsqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName!); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs new file mode 100644 index 000000000..52f3d07f7 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs @@ -0,0 +1,40 @@ +using LINGYUN.Abp.Saas.Tenants; +using Microsoft.Data.SqlClient; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Saas.SqlServer; + +public class SqlServerConnectionStringChecker : IDataBaseConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new SqlConnectionStringBuilder(connectionString) + { + ConnectTimeout = 1 + }; + + var oldDatabaseName = connString.InitialCatalog; + connString.InitialCatalog = "master"; + + try + { + await using var conn = new SqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs new file mode 100644 index 000000000..747309900 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs @@ -0,0 +1,33 @@ +using LINGYUN.Abp.Saas.Tenants; +using Microsoft.Data.Sqlite; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Saas.Sqlite; + +public class SqliteConnectionStringChecker : IDataBaseConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + + try + { + await using var conn = new SqliteConnection(connectionString); + await conn.OpenAsync(); + result.Connected = true; + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} + diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs index ed946d9a7..4103cbb9c 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs @@ -20,7 +20,7 @@ public static class AbpSaasErrorCodes /// public const string TenantIdOrNameNotFound = Namespace + ":020002"; /// - /// 无效的默认连接字符串 + /// 无法打开默认连接字符串指向的数据库连接 /// public const string InvalidDefaultConnectionString = Namespace + ":020101"; /// @@ -31,4 +31,8 @@ public static class AbpSaasErrorCodes /// {Name} 的连接字符串无效 /// public const string InvalidConnectionString = Namespace + ":020103"; + /// + /// 不支持 {Name} 类型的数据库连接检查 + /// + public const string ConnectionStringProviderNotSupport = Namespace + ":020104"; } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json index 8d13828e7..8d976749b 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json @@ -8,6 +8,7 @@ "Saas:020101": "The default connection string cannot open a connection to the database!", "Saas:020102": "The database pointed to by the default connection string already exists!", "Saas:020103": "Unable to open the database connection pointed to by {Name}!", + "Saas:020104": "Database connection check of the {Name} type is not supported!", "Volo.AbpIo.MultiTenancy:010001": "The tenant is unavailable or restricted!", "Volo.AbpIo.MultiTenancy:010002": "Tenant unavailable!", "Menu:Saas": "Saas", @@ -25,6 +26,7 @@ "ConnectionStrings:AddNew": "New Connection", "DisplayName:DefaultConnectionString": "Default Connection String", "DisplayName:UseSharedDatabase": "Use the Shared Database", + "DisplayName:DataBaseProvider": "Data Base Provider", "DisplayName:Name": "Name", "DisplayName:Value": "Value", "DisplayName:IsActive": "Active", diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json index 26caa8a45..21dba4be6 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json @@ -8,6 +8,7 @@ "Saas:020101": "无法打开默认连接字符串指向的数据库连接!", "Saas:020102": "默认连接字符串指向的数据库已经存在!", "Saas:020103": "无法打开 {Name} 指向的数据库连接!", + "Saas:020104": "不支持 {Name} 类型的数据库连接检查!", "Volo.AbpIo.MultiTenancy:010001": "租户不可用或受限制!", "Volo.AbpIo.MultiTenancy:010002": "租户不可用!", "Menu:Saas": "Saas", @@ -25,6 +26,7 @@ "ConnectionStrings:AddNew": "添加新连接", "DisplayName:DefaultConnectionString": "默认连接字符串", "DisplayName:UseSharedDatabase": "使用共享数据库", + "DisplayName:DataBaseProvider": "数据库提供者", "DisplayName:Name": "名称", "DisplayName:Value": "值", "DisplayName:IsActive": "启用", diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs new file mode 100644 index 000000000..10c287eb9 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs @@ -0,0 +1,15 @@ +using LINGYUN.Abp.Saas.Tenants; +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Saas; + +public class AbpSaasConnectionStringCheckOptions +{ + public IDictionary ConnectionStringCheckers { get; } + + public AbpSaasConnectionStringCheckOptions() + { + ConnectionStringCheckers = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs new file mode 100644 index 000000000..e79456841 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Data; + +namespace LINGYUN.Abp.Saas.Tenants; + +public class DataBaseConnectionStringCheckResult : AbpConnectionStringCheckResult +{ + public Exception Error { get; set; } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs new file mode 100644 index 000000000..f2ce72c51 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Saas.Tenants; + +public interface IDataBaseConnectionStringChecker +{ + Task CheckAsync(string connectionString); +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs index 9e29feaa9..34120729a 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs @@ -95,4 +95,11 @@ public class TenantController : AbpSaasControllerBase, ITenantAppService { return TenantAppService.DeleteConnectionStringAsync(id, name); } + [HttpPost] + [Route("connection-string/check")] + [Authorize(AbpSaasPermissions.Tenants.ManageConnectionStrings)] + public virtual Task CheckConnectionStringAsync(TenantConnectionStringCheckInput input) + { + return TenantAppService.CheckConnectionStringAsync(input); + } }