Simplify DB to six tables and load credentials via Always Encrypted SonicCredential.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 08:23:55 +02:00
co-authored by Cursor
parent 4d19873776
commit dcfcb5289d
15 changed files with 1356 additions and 461 deletions
+186 -23
View File
@@ -4,6 +4,7 @@ using System.Security.Cryptography.X509Certificates;
using ZA.CoreService.ESBCertificateManager.Configuration;
using ZA.CoreService.ESBCertificateManager.Models;
using ZA.CoreService.ESBCertificateManager.Services;
using ZA.CoreService.ESBCertificateManager.Setup;
using Microsoft.Data.SqlClient;
namespace ZA.CoreService.ESBCertificateManager
@@ -34,10 +35,17 @@ namespace ZA.CoreService.ESBCertificateManager
private DeploymentOrchestrator? _orchestrator;
private readonly SonicConnectionRepository _sonicConnectionRepository;
private readonly DeploymentTargetRepository _deploymentTargetRepository;
private readonly SonicSetupRepository _sonicSetupRepository;
private readonly LocalSetupSelectionStore _localSetupSelectionStore;
private IReadOnlyList<DatabaseSonicConnection>
_databaseSonicConnections = [];
private readonly Dictionary<int, SonicCredentialProfile>
_credentialsByConnectionId = new();
private LocalSetupSelection? _localSetupSelection;
private CertificateInfo? _loadedCertificateInfo;
private IReadOnlyList<DeploymentTarget> _loadedTargets = [];
private bool _isOperationRunning;
@@ -89,6 +97,11 @@ namespace ZA.CoreService.ESBCertificateManager
_deploymentTargetRepository = new DeploymentTargetRepository(
_settings.Database.ConnectionString);
_sonicSetupRepository = new SonicSetupRepository(
_settings.Database.ConnectionString);
_localSetupSelectionStore = new LocalSetupSelectionStore();
BuildDesign();
Shown += async (_, _) => await InitializeApplicationAsync();
@@ -135,6 +148,52 @@ namespace ZA.CoreService.ESBCertificateManager
dragStartPoint = e.Location;
}
}
private async Task OpenSettingsAsync()
{
if (_isOperationRunning)
{
MessageBox.Show(
this,
"Während einer laufenden Aktion können die Einstellungen nicht geöffnet werden.",
"Einstellungen",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
try
{
SetupCoordinator coordinator = new(
_settings,
new SonicSetupRepository(
_settings.Database.ConnectionString));
using SetupWizardForm settingsForm = new(
coordinator,
isSettingsMode: true);
if (settingsForm.ShowDialog(this) != DialogResult.OK)
{
return;
}
SetStatus(
"Einstellungen übernommen. Anwendung wird aktualisiert ...",
isError: false);
await InitializeApplicationAsync();
}
catch (Exception ex)
{
MessageBox.Show(
this,
ex.Message,
"Einstellungen",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private async Task InitializeApplicationAsync()
{
@@ -163,16 +222,32 @@ namespace ZA.CoreService.ESBCertificateManager
}
try
{
_databaseSonicConnections =
await _sonicConnectionRepository.GetActiveAsync();
_localSetupSelection =
_localSetupSelectionStore.Load();
List<SonicConnection> runtimeConnections =
_databaseSonicConnections
.Where(connection => connection.HasCredentials)
.Select(connection =>
_databaseSonicConnections =
await _sonicConnectionRepository.GetActiveAsync(
_settings.EnvironmentCode);
await LoadCredentialsForConnectionsAsync();
List<SonicConnection> runtimeConnections = [];
foreach (DatabaseSonicConnection connection
in _databaseSonicConnections)
{
if (!_credentialsByConnectionId.TryGetValue(
connection.Id,
out SonicCredentialProfile? credential))
{
continue;
}
runtimeConnections.Add(
connection.ToRuntimeConnection(
_settings.Runtime))
.ToList();
_settings.Runtime,
credential));
}
_orchestrator = new DeploymentOrchestrator(
_settings,
@@ -195,12 +270,13 @@ namespace ZA.CoreService.ESBCertificateManager
SetStatus(
$"{_databaseSonicConnections.Count} aktive Sonic-Verbindung(en) " +
$"aus SQL und {_loadedTargets.Count} lokale Testziele geladen.",
$"aus SQL und {_loadedTargets.Count} Bereitstellungsziel(e) geladen.",
isError: false);
}
catch (SqlException ex)
{
_databaseSonicConnections = [];
_credentialsByConnectionId.Clear();
SetStatus(
$"SQL-Zugriff fehlgeschlagen: {ex.Message}",
@@ -485,12 +561,12 @@ namespace ZA.CoreService.ESBCertificateManager
progressPanel.Controls.Add(progressTitle);
// -----------------------------
// 3. Footer unten: Version
// 3. Footer unten: Einstellungen + Version
// -----------------------------
Panel footerPanel = new Panel
{
Dock = DockStyle.Bottom,
Height = 70,
Height = 118,
Padding = new Padding(18, 8, 12, 8)
};
@@ -501,13 +577,36 @@ namespace ZA.CoreService.ESBCertificateManager
BackColor = BorderColor
};
Button btnSettings = new Button
{
Text = " Einstellungen",
Location = new Point(14, 14),
Size = new Size(176, 36),
FlatStyle = FlatStyle.Flat,
FlatAppearance =
{
BorderSize = 1,
BorderColor = BorderColor,
MouseOverBackColor = Color.FromArgb(37, 52, 74)
},
BackColor = SidebarColor,
ForeColor = TextColor,
Font = new Font("Segoe UI", 9, FontStyle.Bold),
TextAlign = ContentAlignment.MiddleLeft,
Cursor = Cursors.Hand,
Enabled = !_isOperationRunning
};
btnSettings.Click += async (_, _) =>
await OpenSettingsAsync();
Label versionLabel = new Label
{
Text = "INTERNAL TOOL",
ForeColor = MutedTextColor,
Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
AutoSize = true,
Location = new Point(18, 17)
Location = new Point(18, 62)
};
Label versionNumber = new Label
@@ -516,10 +615,11 @@ namespace ZA.CoreService.ESBCertificateManager
ForeColor = BlueColor,
Font = new Font("Segoe UI", 8),
AutoSize = true,
Location = new Point(18, 37)
Location = new Point(18, 82)
};
footerPanel.Controls.Add(footerSeparator);
footerPanel.Controls.Add(btnSettings);
footerPanel.Controls.Add(versionLabel);
footerPanel.Controls.Add(versionNumber);
@@ -1428,7 +1528,8 @@ namespace ZA.CoreService.ESBCertificateManager
isError: false);
_loadedTargets =
await _deploymentTargetRepository.GetActiveAsync();
await _deploymentTargetRepository.GetActiveAsync(
_settings.EnvironmentCode);
BindTargetsToGrid(_loadedTargets);
@@ -1943,6 +2044,42 @@ namespace ZA.CoreService.ESBCertificateManager
// ---------------------------------------------------------------
// Sonic Status (KnownContainers aus appsettings)
// ---------------------------------------------------------------
private async Task LoadCredentialsForConnectionsAsync()
{
_credentialsByConnectionId.Clear();
foreach (DatabaseSonicConnection connection
in _databaseSonicConnections)
{
IReadOnlyList<SonicCredentialProfile> profiles =
await _sonicSetupRepository.GetCredentialsAsync(
connection.Id);
SonicCredentialProfile? selected = null;
if (_localSetupSelection is not null
&& _localSetupSelection.SonicConnectionId
== connection.Id
&& _localSetupSelection.SonicCredentialId > 0)
{
selected = profiles.FirstOrDefault(
profile =>
profile.SonicCredentialId
== _localSetupSelection.SonicCredentialId);
}
selected ??=
profiles.FirstOrDefault(profile => profile.IsDefault)
?? profiles.FirstOrDefault();
if (selected is not null && selected.IsComplete)
{
_credentialsByConnectionId[connection.Id] =
selected;
}
}
}
private void BindDatabaseSonicConnections()
{
cmbSonicConnection.Items.Clear();
@@ -1953,13 +2090,34 @@ namespace ZA.CoreService.ESBCertificateManager
cmbSonicConnection.Items.Add(connection.Name);
}
if (cmbSonicConnection.Items.Count > 0)
if (cmbSonicConnection.Items.Count == 0)
{
cmbSonicConnection.SelectedIndex = 0;
RefreshSonicStatusLine();
return;
}
RefreshSonicStatusLine();
int preferredIndex = 0;
if (_localSetupSelection is not null
&& !string.IsNullOrWhiteSpace(
_localSetupSelection.ConnectionName))
{
for (int index = 0;
index < cmbSonicConnection.Items.Count;
index++)
{
if (string.Equals(
cmbSonicConnection.Items[index]?.ToString(),
_localSetupSelection.ConnectionName,
StringComparison.OrdinalIgnoreCase))
{
preferredIndex = index;
break;
}
}
}
cmbSonicConnection.SelectedIndex = preferredIndex;
}
private void BuildSonicDiscoveryRow(Panel card)
{
@@ -2036,14 +2194,19 @@ namespace ZA.CoreService.ESBCertificateManager
{
string connectionUrl = connection.BuildConnectionUrl();
bool hasCredentialReference =
!string.IsNullOrWhiteSpace(connection.CredentialReference);
bool hasCredential =
_credentialsByConnectionId.TryGetValue(
connection.Id,
out SonicCredentialProfile? credential);
lblSonicStatus.Text = hasCredentialReference
? $"{connection.Name}: {connectionUrl}, Credential-Referenz vorhanden"
: $"{connection.Name}: {connectionUrl}, sichere Zugangsdaten noch nicht konfiguriert";
string credentialInfo = hasCredential
? $"Profil '{credential!.CredentialName}'"
: "sichere Zugangsdaten noch nicht konfiguriert";
lblSonicStatus.ForeColor = hasCredentialReference
lblSonicStatus.Text =
$"{connection.Name}: {connectionUrl}, {credentialInfo}";
lblSonicStatus.ForeColor = hasCredential
? GreenColor
: GoldColor;
}