Files
123123/ZA.CoreService.ESBCertificateManager/Services/SonicSetupRepository.cs
T

1325 lines
39 KiB
C#

using System.Data;
using Microsoft.Data.SqlClient;
using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
public sealed class SonicSetupRepository
{
private readonly string _connectionString;
public SonicSetupRepository(string connectionString)
{
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new ArgumentException(
"Der SQL-Connection-String fehlt.",
nameof(connectionString));
}
_connectionString = connectionString;
}
public async Task<IReadOnlyList<SonicSystemOption>> GetSystemsAsync(
string environmentCode,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(environmentCode))
{
throw new ArgumentException(
"Der EnvironmentCode fehlt.",
nameof(environmentCode));
}
const string sql = """
SELECT
connection.[SonicConnectionId],
connection.[ConnectionName],
environment.[EnvironmentCode],
connection.[DomainName],
connection.[ManagementHost],
connection.[ManagementPort],
connection.[ConnectionProtocol],
MIN(container.[ContainerName])
AS [ValidationContainerName]
FROM [dbo].[SonicConnection] AS connection
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] =
connection.[EnvironmentId]
LEFT JOIN [dbo].[SonicContainer] AS container
ON container.[SonicConnectionId] =
connection.[SonicConnectionId]
AND container.[IsActive] = 1
WHERE connection.[IsActive] = 1
AND environment.[IsActive] = 1
AND environment.[EnvironmentCode] =
@EnvironmentCode
GROUP BY
connection.[SonicConnectionId],
connection.[ConnectionName],
environment.[EnvironmentCode],
connection.[DomainName],
connection.[ManagementHost],
connection.[ManagementPort],
connection.[ConnectionProtocol]
ORDER BY connection.[ConnectionName];
""";
List<SonicSystemOption> systems = [];
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@EnvironmentCode",
SqlDbType.NVarChar,
30)
{
Value = environmentCode
.Trim()
.ToUpperInvariant()
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
int sonicConnectionIdOrdinal =
reader.GetOrdinal("SonicConnectionId");
int connectionNameOrdinal =
reader.GetOrdinal("ConnectionName");
int environmentCodeOrdinal =
reader.GetOrdinal("EnvironmentCode");
int domainNameOrdinal =
reader.GetOrdinal("DomainName");
int managementHostOrdinal =
reader.GetOrdinal("ManagementHost");
int managementPortOrdinal =
reader.GetOrdinal("ManagementPort");
int connectionProtocolOrdinal =
reader.GetOrdinal("ConnectionProtocol");
int validationContainerNameOrdinal =
reader.GetOrdinal("ValidationContainerName");
while (await reader.ReadAsync(cancellationToken))
{
systems.Add(
new SonicSystemOption
{
SonicConnectionId =
reader.GetInt32(
sonicConnectionIdOrdinal),
ConnectionName =
reader.GetString(
connectionNameOrdinal),
EnvironmentCode =
reader.GetString(
environmentCodeOrdinal),
DomainName =
reader.IsDBNull(domainNameOrdinal)
? string.Empty
: reader.GetString(
domainNameOrdinal),
ManagementHost =
reader.GetString(
managementHostOrdinal),
ManagementPort =
reader.GetInt32(
managementPortOrdinal),
ConnectionProtocol =
reader.IsDBNull(connectionProtocolOrdinal)
? "tcp"
: reader.GetString(
connectionProtocolOrdinal),
ValidationContainerName =
reader.IsDBNull(
validationContainerNameOrdinal)
? string.Empty
: reader.GetString(
validationContainerNameOrdinal)
});
}
return systems;
}
public async Task<int> AddCredentialAsync(
int sonicConnectionId,
string credentialName,
string userName,
string secret,
bool isDefault,
CancellationToken cancellationToken = default)
{
if (sonicConnectionId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicConnectionId));
}
if (string.IsNullOrWhiteSpace(credentialName))
{
throw new ArgumentException(
"Der Profilname fehlt.",
nameof(credentialName));
}
if (string.IsNullOrWhiteSpace(userName))
{
throw new ArgumentException(
"Der Sonic-Benutzername fehlt.",
nameof(userName));
}
if (string.IsNullOrEmpty(secret))
{
throw new ArgumentException(
"Das Sonic-Kennwort fehlt.",
nameof(secret));
}
string normalizedCredentialName =
credentialName.Trim();
string normalizedUserName =
userName.Trim();
if (normalizedCredentialName.Length > 150)
{
throw new ArgumentException(
"Der Profilname darf maximal 150 Zeichen enthalten.",
nameof(credentialName));
}
if (normalizedUserName.Length > 256)
{
throw new ArgumentException(
"Der Benutzername darf maximal 256 Zeichen enthalten.",
nameof(userName));
}
if (secret.Length > 512)
{
throw new ArgumentException(
"Das Kennwort darf maximal 512 Zeichen enthalten.",
nameof(secret));
}
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlTransaction transaction =
(SqlTransaction)
await connection.BeginTransactionAsync(
cancellationToken);
try
{
if (isDefault)
{
const string clearDefaultSql = """
UPDATE [dbo].[SonicCredential]
SET
[IsDefault] = 0,
[ModifiedDateTime] = SYSUTCDATETIME(),
[ModifiedBy] = SUSER_SNAME()
WHERE [SonicConnectionId] =
@SonicConnectionId
AND [IsDefault] = 1;
""";
await using SqlCommand clearDefaultCommand =
new(
clearDefaultSql,
connection,
transaction);
clearDefaultCommand.Parameters.Add(
new SqlParameter(
"@SonicConnectionId",
SqlDbType.Int)
{
Value = sonicConnectionId
});
await clearDefaultCommand.ExecuteNonQueryAsync(
cancellationToken);
}
const string insertSql = """
INSERT INTO [dbo].[SonicCredential]
(
[SonicConnectionId],
[CredentialName],
[CredentialUserName],
[CredentialSecret],
[IsDefault],
[IsActive],
[CreationDateTime],
[CreatedBy],
[ModifiedDateTime],
[ModifiedBy]
)
OUTPUT INSERTED.[SonicCredentialId]
VALUES
(
@SonicConnectionId,
@CredentialName,
@CredentialUserName,
@CredentialSecret,
@IsDefault,
1,
SYSUTCDATETIME(),
SUSER_SNAME(),
NULL,
NULL
);
""";
await using SqlCommand insertCommand =
new(
insertSql,
connection,
transaction);
insertCommand.Parameters.Add(
new SqlParameter(
"@SonicConnectionId",
SqlDbType.Int)
{
Value = sonicConnectionId
});
insertCommand.Parameters.Add(
new SqlParameter(
"@CredentialName",
SqlDbType.NVarChar,
150)
{
Value = normalizedCredentialName
});
insertCommand.Parameters.Add(
new SqlParameter(
"@CredentialUserName",
SqlDbType.NVarChar,
256)
{
Value = normalizedUserName
});
insertCommand.Parameters.Add(
new SqlParameter(
"@CredentialSecret",
SqlDbType.NVarChar,
512)
{
Value = secret
});
insertCommand.Parameters.Add(
new SqlParameter(
"@IsDefault",
SqlDbType.Bit)
{
Value = isDefault
});
object? result =
await insertCommand.ExecuteScalarAsync(
cancellationToken);
if (result is null || result is DBNull)
{
throw new InvalidOperationException(
"Das Benutzerprofil konnte nicht angelegt werden.");
}
int credentialId =
Convert.ToInt32(result);
await transaction.CommitAsync(
cancellationToken);
return credentialId;
}
catch
{
try
{
await transaction.RollbackAsync(
CancellationToken.None);
}
catch
{
// Die ursprüngliche Exception soll erhalten bleiben.
}
throw;
}
}
public async Task<IReadOnlyList<SonicCredentialProfile>>
GetCredentialsAsync(
int sonicConnectionId,
CancellationToken cancellationToken = default)
{
if (sonicConnectionId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicConnectionId));
}
const string sql = """
SELECT
[SonicCredentialId],
[SonicConnectionId],
[CredentialName],
[CredentialUserName],
[CredentialSecret],
[IsDefault],
[IsActive]
FROM [dbo].[SonicCredential]
WHERE [SonicConnectionId] = @SonicConnectionId
AND [IsActive] = 1
ORDER BY
[IsDefault] DESC,
[CredentialName];
""";
List<SonicCredentialProfile> profiles = [];
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@SonicConnectionId",
SqlDbType.Int)
{
Value = sonicConnectionId
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
int credentialIdOrdinal =
reader.GetOrdinal("SonicCredentialId");
int connectionIdOrdinal =
reader.GetOrdinal("SonicConnectionId");
int credentialNameOrdinal =
reader.GetOrdinal("CredentialName");
int userNameOrdinal =
reader.GetOrdinal("CredentialUserName");
int secretOrdinal =
reader.GetOrdinal("CredentialSecret");
int isDefaultOrdinal =
reader.GetOrdinal("IsDefault");
int isActiveOrdinal =
reader.GetOrdinal("IsActive");
while (await reader.ReadAsync(cancellationToken))
{
string? userName =
reader.IsDBNull(userNameOrdinal)
? null
: reader.GetString(userNameOrdinal);
string? secret =
reader.IsDBNull(secretOrdinal)
? null
: reader.GetString(secretOrdinal);
if (string.IsNullOrWhiteSpace(userName)
|| string.IsNullOrEmpty(secret))
{
continue;
}
profiles.Add(
new SonicCredentialProfile
{
SonicCredentialId =
reader.GetInt32(
credentialIdOrdinal),
SonicConnectionId =
reader.GetInt32(
connectionIdOrdinal),
CredentialName =
reader.GetString(
credentialNameOrdinal),
UserName = userName,
Secret = secret,
IsDefault =
reader.GetBoolean(
isDefaultOrdinal),
IsActive =
reader.GetBoolean(
isActiveOrdinal)
});
}
return profiles;
}
public async Task<SonicCredentialProfile?> GetCredentialByIdAsync(
int sonicCredentialId,
CancellationToken cancellationToken = default)
{
if (sonicCredentialId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicCredentialId));
}
const string sql = """
SELECT
[SonicCredentialId],
[SonicConnectionId],
[CredentialName],
[CredentialUserName],
[CredentialSecret],
[IsDefault],
[IsActive]
FROM [dbo].[SonicCredential]
WHERE [SonicCredentialId] = @SonicCredentialId
AND [IsActive] = 1;
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@SonicCredentialId",
SqlDbType.Int)
{
Value = sonicCredentialId
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
if (!await reader.ReadAsync(cancellationToken))
{
return null;
}
int userNameOrdinal =
reader.GetOrdinal("CredentialUserName");
int secretOrdinal =
reader.GetOrdinal("CredentialSecret");
string? userName =
reader.IsDBNull(userNameOrdinal)
? null
: reader.GetString(userNameOrdinal);
string? secret =
reader.IsDBNull(secretOrdinal)
? null
: reader.GetString(secretOrdinal);
if (string.IsNullOrWhiteSpace(userName)
|| string.IsNullOrEmpty(secret))
{
return null;
}
return new SonicCredentialProfile
{
SonicCredentialId =
reader.GetInt32(
reader.GetOrdinal("SonicCredentialId")),
SonicConnectionId =
reader.GetInt32(
reader.GetOrdinal("SonicConnectionId")),
CredentialName =
reader.GetString(
reader.GetOrdinal("CredentialName")),
UserName = userName,
Secret = secret,
IsDefault =
reader.GetBoolean(
reader.GetOrdinal("IsDefault")),
IsActive =
reader.GetBoolean(
reader.GetOrdinal("IsActive"))
};
}
public async Task<IReadOnlyList<CompanyOption>> GetCompaniesAsync(
CancellationToken cancellationToken = default)
{
const string sql = """
SELECT
[CompanyId],
[CompanyCode],
[CompanyName]
FROM [dbo].[Company]
WHERE [IsActive] = 1
ORDER BY [CompanyCode];
""";
List<CompanyOption> companies = [];
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
companies.Add(
new CompanyOption
{
CompanyId =
reader.GetInt32(
reader.GetOrdinal("CompanyId")),
CompanyCode =
reader.GetString(
reader.GetOrdinal("CompanyCode")),
CompanyName =
reader.GetString(
reader.GetOrdinal("CompanyName"))
});
}
return companies;
}
public async Task<IReadOnlyList<ContainerOption>> GetContainersAsync(
string environmentCode,
int? sonicConnectionId = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(environmentCode))
{
throw new ArgumentException(
"Der EnvironmentCode fehlt.",
nameof(environmentCode));
}
const string sql = """
SELECT
container.[SonicContainerId],
container.[SonicConnectionId],
container.[CompanyId],
container.[ContainerName],
container.[ContainerDisplayName],
container.[RestartTimeoutSeconds],
company.[CompanyCode],
connection.[ConnectionName]
FROM [dbo].[SonicContainer] AS container
INNER JOIN [dbo].[Company] AS company
ON company.[CompanyId] = container.[CompanyId]
INNER JOIN [dbo].[SonicConnection] AS connection
ON connection.[SonicConnectionId] =
container.[SonicConnectionId]
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] =
connection.[EnvironmentId]
WHERE container.[IsActive] = 1
AND company.[IsActive] = 1
AND connection.[IsActive] = 1
AND environment.[IsActive] = 1
AND environment.[EnvironmentCode] = @EnvironmentCode
AND
(
@SonicConnectionId IS NULL
OR container.[SonicConnectionId] = @SonicConnectionId
)
ORDER BY
company.[CompanyCode],
container.[ContainerName];
""";
List<ContainerOption> containers = [];
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@EnvironmentCode",
SqlDbType.NVarChar,
30)
{
Value = environmentCode
.Trim()
.ToUpperInvariant()
});
command.Parameters.Add(
new SqlParameter(
"@SonicConnectionId",
SqlDbType.Int)
{
Value = sonicConnectionId is null or <= 0
? DBNull.Value
: sonicConnectionId.Value
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
int displayOrdinal =
reader.GetOrdinal("ContainerDisplayName");
containers.Add(
new ContainerOption
{
SonicContainerId =
reader.GetInt32(
reader.GetOrdinal("SonicContainerId")),
SonicConnectionId =
reader.GetInt32(
reader.GetOrdinal("SonicConnectionId")),
CompanyId =
reader.GetInt32(
reader.GetOrdinal("CompanyId")),
ContainerName =
reader.GetString(
reader.GetOrdinal("ContainerName")),
ContainerDisplayName =
reader.IsDBNull(displayOrdinal)
? null
: reader.GetString(displayOrdinal),
RestartTimeoutSeconds =
reader.GetInt32(
reader.GetOrdinal("RestartTimeoutSeconds")),
CompanyCode =
reader.GetString(
reader.GetOrdinal("CompanyCode")),
ConnectionName =
reader.GetString(
reader.GetOrdinal("ConnectionName"))
});
}
return containers;
}
public async Task<IReadOnlyList<CertificateTargetOption>>
GetCertificateTargetsAsync(
string environmentCode,
int? sonicContainerId = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(environmentCode))
{
throw new ArgumentException(
"Der EnvironmentCode fehlt.",
nameof(environmentCode));
}
const string sql = """
SELECT
target.[CertificateTargetId],
target.[SonicContainerId],
target.[TargetDirectory],
target.[TargetFileName],
target.[BackupEnabled],
target.[BackupDirectoryName],
container.[ContainerName],
connection.[ConnectionName],
company.[CompanyCode]
FROM [dbo].[CertificateTarget] AS target
INNER JOIN [dbo].[SonicContainer] AS container
ON container.[SonicContainerId] =
target.[SonicContainerId]
INNER JOIN [dbo].[SonicConnection] AS connection
ON connection.[SonicConnectionId] =
container.[SonicConnectionId]
INNER JOIN [dbo].[Company] AS company
ON company.[CompanyId] = container.[CompanyId]
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] =
connection.[EnvironmentId]
WHERE target.[IsActive] = 1
AND container.[IsActive] = 1
AND connection.[IsActive] = 1
AND company.[IsActive] = 1
AND environment.[IsActive] = 1
AND environment.[EnvironmentCode] = @EnvironmentCode
AND
(
@SonicContainerId IS NULL
OR target.[SonicContainerId] = @SonicContainerId
)
ORDER BY
company.[CompanyCode],
container.[ContainerName],
target.[TargetDirectory],
target.[TargetFileName];
""";
List<CertificateTargetOption> targets = [];
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@EnvironmentCode",
SqlDbType.NVarChar,
30)
{
Value = environmentCode
.Trim()
.ToUpperInvariant()
});
command.Parameters.Add(
new SqlParameter(
"@SonicContainerId",
SqlDbType.Int)
{
Value = sonicContainerId is null or <= 0
? DBNull.Value
: sonicContainerId.Value
});
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
targets.Add(
new CertificateTargetOption
{
CertificateTargetId =
reader.GetInt32(
reader.GetOrdinal("CertificateTargetId")),
SonicContainerId =
reader.GetInt32(
reader.GetOrdinal("SonicContainerId")),
TargetDirectory =
reader.GetString(
reader.GetOrdinal("TargetDirectory")),
TargetFileName =
reader.GetString(
reader.GetOrdinal("TargetFileName")),
BackupEnabled =
reader.GetBoolean(
reader.GetOrdinal("BackupEnabled")),
BackupDirectoryName =
reader.GetString(
reader.GetOrdinal("BackupDirectoryName")),
ContainerName =
reader.GetString(
reader.GetOrdinal("ContainerName")),
ConnectionName =
reader.GetString(
reader.GetOrdinal("ConnectionName")),
CompanyCode =
reader.GetString(
reader.GetOrdinal("CompanyCode"))
});
}
return targets;
}
public async Task<int> AddSonicConnectionAsync(
string environmentCode,
string connectionName,
string managementHost,
int managementPort,
string domainName,
string connectionProtocol,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(environmentCode))
{
throw new ArgumentException(
"Der EnvironmentCode fehlt.",
nameof(environmentCode));
}
string name = RequireTrimmed(
connectionName,
150,
"ConnectionName");
string host = RequireTrimmed(
managementHost,
255,
"ManagementHost");
string domain = RequireTrimmed(
domainName,
150,
"DomainName");
string protocol = string.IsNullOrWhiteSpace(connectionProtocol)
? "tcp"
: connectionProtocol.Trim().TrimEnd(':', '/');
if (managementPort is < 1 or > 65535)
{
throw new ArgumentOutOfRangeException(
nameof(managementPort),
"Der ManagementPort muss zwischen 1 und 65535 liegen.");
}
const string sql = """
INSERT INTO [dbo].[SonicConnection]
(
[EnvironmentId],
[ConnectionName],
[ManagementHost],
[ManagementPort],
[DomainName],
[ConnectionProtocol],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
OUTPUT INSERTED.[SonicConnectionId]
SELECT
environment.[EnvironmentId],
@ConnectionName,
@ManagementHost,
@ManagementPort,
@DomainName,
@ConnectionProtocol,
1,
SYSUTCDATETIME(),
SUSER_SNAME()
FROM [dbo].[Environment] AS environment
WHERE environment.[EnvironmentCode] = @EnvironmentCode
AND environment.[IsActive] = 1;
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter(
"@EnvironmentCode",
SqlDbType.NVarChar,
30)
{
Value = environmentCode
.Trim()
.ToUpperInvariant()
});
command.Parameters.Add(
new SqlParameter(
"@ConnectionName",
SqlDbType.NVarChar,
150)
{
Value = name
});
command.Parameters.Add(
new SqlParameter(
"@ManagementHost",
SqlDbType.NVarChar,
255)
{
Value = host
});
command.Parameters.Add(
new SqlParameter(
"@ManagementPort",
SqlDbType.Int)
{
Value = managementPort
});
command.Parameters.Add(
new SqlParameter(
"@DomainName",
SqlDbType.NVarChar,
150)
{
Value = domain
});
command.Parameters.Add(
new SqlParameter(
"@ConnectionProtocol",
SqlDbType.NVarChar,
20)
{
Value = protocol
});
object? result =
await command.ExecuteScalarAsync(cancellationToken);
if (result is null || result is DBNull)
{
throw new InvalidOperationException(
$"Die Umgebung '{environmentCode}' wurde nicht gefunden " +
"oder die Sonic-Verbindung konnte nicht angelegt werden.");
}
return Convert.ToInt32(result);
}
public async Task<int> AddSonicContainerAsync(
int companyId,
int sonicConnectionId,
string containerName,
string? containerDisplayName,
int restartTimeoutSeconds,
CancellationToken cancellationToken = default)
{
if (companyId <= 0)
{
throw new ArgumentOutOfRangeException(nameof(companyId));
}
if (sonicConnectionId <= 0)
{
throw new ArgumentOutOfRangeException(nameof(sonicConnectionId));
}
string name = RequireTrimmed(
containerName,
250,
"ContainerName");
string? display =
string.IsNullOrWhiteSpace(containerDisplayName)
? null
: containerDisplayName.Trim();
if (display is { Length: > 250 })
{
throw new ArgumentException(
"Der Anzeigename darf maximal 250 Zeichen enthalten.",
nameof(containerDisplayName));
}
if (restartTimeoutSeconds is < 10 or > 3600)
{
throw new ArgumentOutOfRangeException(
nameof(restartTimeoutSeconds),
"Timeout muss zwischen 10 und 3600 Sekunden liegen.");
}
const string sql = """
INSERT INTO [dbo].[SonicContainer]
(
[CompanyId],
[SonicConnectionId],
[ContainerName],
[ContainerDisplayName],
[RestartTimeoutSeconds],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
OUTPUT INSERTED.[SonicContainerId]
VALUES
(
@CompanyId,
@SonicConnectionId,
@ContainerName,
@ContainerDisplayName,
@RestartTimeoutSeconds,
1,
SYSUTCDATETIME(),
SUSER_SNAME()
);
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter("@CompanyId", SqlDbType.Int)
{
Value = companyId
});
command.Parameters.Add(
new SqlParameter("@SonicConnectionId", SqlDbType.Int)
{
Value = sonicConnectionId
});
command.Parameters.Add(
new SqlParameter(
"@ContainerName",
SqlDbType.NVarChar,
250)
{
Value = name
});
command.Parameters.Add(
new SqlParameter(
"@ContainerDisplayName",
SqlDbType.NVarChar,
250)
{
Value = display is null
? DBNull.Value
: display
});
command.Parameters.Add(
new SqlParameter(
"@RestartTimeoutSeconds",
SqlDbType.Int)
{
Value = restartTimeoutSeconds
});
object? result =
await command.ExecuteScalarAsync(cancellationToken);
if (result is null || result is DBNull)
{
throw new InvalidOperationException(
"Der Container konnte nicht angelegt werden.");
}
return Convert.ToInt32(result);
}
public async Task<int> AddCertificateTargetAsync(
int sonicContainerId,
string targetDirectory,
string targetFileName,
bool backupEnabled,
string backupDirectoryName,
CancellationToken cancellationToken = default)
{
if (sonicContainerId <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(sonicContainerId));
}
string directory = RequireTrimmed(
targetDirectory,
500,
"TargetDirectory");
string fileName = RequireTrimmed(
targetFileName,
260,
"TargetFileName");
string backupName = string.IsNullOrWhiteSpace(backupDirectoryName)
? "Backup"
: backupDirectoryName.Trim();
if (backupName.Length > 100)
{
throw new ArgumentException(
"Der Backup-Ordnername darf maximal 100 Zeichen enthalten.",
nameof(backupDirectoryName));
}
const string sql = """
INSERT INTO [dbo].[CertificateTarget]
(
[SonicContainerId],
[TargetDirectory],
[TargetFileName],
[BackupEnabled],
[BackupDirectoryName],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
OUTPUT INSERTED.[CertificateTargetId]
VALUES
(
@SonicContainerId,
@TargetDirectory,
@TargetFileName,
@BackupEnabled,
@BackupDirectoryName,
1,
SYSUTCDATETIME(),
SUSER_SNAME()
);
""";
await using SqlConnection connection =
new(_connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlCommand command =
new(sql, connection);
command.Parameters.Add(
new SqlParameter("@SonicContainerId", SqlDbType.Int)
{
Value = sonicContainerId
});
command.Parameters.Add(
new SqlParameter(
"@TargetDirectory",
SqlDbType.NVarChar,
500)
{
Value = directory
});
command.Parameters.Add(
new SqlParameter(
"@TargetFileName",
SqlDbType.NVarChar,
260)
{
Value = fileName
});
command.Parameters.Add(
new SqlParameter("@BackupEnabled", SqlDbType.Bit)
{
Value = backupEnabled
});
command.Parameters.Add(
new SqlParameter(
"@BackupDirectoryName",
SqlDbType.NVarChar,
100)
{
Value = backupName
});
object? result =
await command.ExecuteScalarAsync(cancellationToken);
if (result is null || result is DBNull)
{
throw new InvalidOperationException(
"Das Zertifikat-Ziel konnte nicht angelegt werden.");
}
return Convert.ToInt32(result);
}
private static string RequireTrimmed(
string? value,
int maxLength,
string fieldName)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException(
$"'{fieldName}' fehlt.");
}
string trimmed = value.Trim();
if (trimmed.Length > maxLength)
{
throw new ArgumentException(
$"'{fieldName}' darf maximal {maxLength} Zeichen enthalten.");
}
return trimmed;
}
}