Browse Source

feat(saas): Added database connection string check

pull/1161/head
colin 10 months ago
parent
commit
2959f4ad50
  1. 18
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs
  2. 15
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs
  3. 2
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs
  4. 54
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs
  5. 3
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml
  6. 30
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd
  7. 28
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj
  8. 24
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs
  9. 39
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs
  10. 35
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs
  11. 40
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs
  12. 40
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs
  13. 33
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs
  14. 6
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs
  15. 2
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json
  16. 2
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json
  17. 15
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs
  18. 9
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs
  19. 8
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs
  20. 7
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs

18
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; }
}

15
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;
}
}

2
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);
}

54
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<AbpSaasConnectionStringCheckOptions> connectionStringCheckOptions)
{
EventBus = eventBus;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
ConnectionStringChecker = connectionStringChecker;
ConnectionStringCheckOptions = connectionStringCheckOptions.Value;
}
public async virtual Task<TenantDto> 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<TenantConnectionStringDto> 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);
//}
}
}

3
aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

28
aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.Saas.DbChecker</AssemblyName>
<PackageId>LINGYUN.Abp.Saas.DbChecker</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySqlConnector" />
<PackageReference Include="Oracle.ManagedDataAccess.Core" />
<PackageReference Include="Npgsql" />
<PackageReference Include="Microsoft.Data.SqlClient" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Saas.Domain\LINGYUN.Abp.Saas.Domain.csproj" />
</ItemGroup>
</Project>

24
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<AbpSaasConnectionStringCheckOptions>(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();
});
}
}

39
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<DataBaseConnectionStringCheckResult> 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;
}
}
}

35
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<DataBaseConnectionStringCheckResult> 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;
}
}
}

40
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<DataBaseConnectionStringCheckResult> 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;
}
}
}

40
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<DataBaseConnectionStringCheckResult> 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;
}
}
}

33
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<DataBaseConnectionStringCheckResult> 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;
}
}
}

6
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs

@ -20,7 +20,7 @@ public static class AbpSaasErrorCodes
/// </summary>
public const string TenantIdOrNameNotFound = Namespace + ":020002";
/// <summary>
/// 无效的默认连接字符串
/// 无法打开默认连接字符串指向的数据库连接
/// </summary>
public const string InvalidDefaultConnectionString = Namespace + ":020101";
/// <summary>
@ -31,4 +31,8 @@ public static class AbpSaasErrorCodes
/// {Name} 的连接字符串无效
/// </summary>
public const string InvalidConnectionString = Namespace + ":020103";
/// <summary>
/// 不支持 {Name} 类型的数据库连接检查
/// </summary>
public const string ConnectionStringProviderNotSupport = Namespace + ":020104";
}

2
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",

2
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": "启用",

15
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<string, IDataBaseConnectionStringChecker> ConnectionStringCheckers { get; }
public AbpSaasConnectionStringCheckOptions()
{
ConnectionStringCheckers = new Dictionary<string, IDataBaseConnectionStringChecker>(StringComparer.InvariantCultureIgnoreCase);
}
}

9
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; }
}

8
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<DataBaseConnectionStringCheckResult> CheckAsync(string connectionString);
}

7
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);
}
}

Loading…
Cancel
Save