Inhaltsverzeichnis
Connection Manager
Der Connection Manager (IWvdSConnectionManager) ist ein provider-agnostischer Connection Broker auf IHost. Er verwaltet benannte Datenverbindungen zentral für alle Add-ins. Ziel ist eine einheitliche Schnittstelle, über die jedes Add-in auf konfigurierte Datenquellen zugreift, ohne selbst Verbindungsparameter, Treibererkennung oder Instanz-Lebenszyklus verwalten zu müssen. Im Unterschied zu einer direkten Provider-Erzeugung im Add-in-Code liegt die gesamte Konfiguration in der user.config.json — Änderungen an Verbindungsparametern erfordern keinen Code-Eingriff. Der Vorteil besteht darin, dass alle Add-ins dieselbe Provider-Instanz teilen und der Host den Lebenszyklus kontrolliert.
Erreichbar über FHost.Connections.
Zurück zur Service-Referenz oder zur SDK-Übersicht.
Architektur
Der Connection Manager arbeitet in drei Phasen:
- Konfiguration lesen: Beim Start liest die Shell das
connections-Array aus deruser.config.json. Jede Verbindung hat einen Namen, einen Provider-Typ und ein Array mit provider-spezifischen Feldwerten. - Factory-Registry: Für jeden Provider-Typ (
mssql,rest,sqlite, etc.) existiert eineIWvdSProviderFactory. Der Host registriert eine eingebaute Factory fürmssql(ODBC Driver 17/18). Add-ins können eigene Factories für weitere Provider-Typen registrieren. - Lazy Singleton: Provider-Instanzen werden erst beim ersten
GetConnection-Aufruf erzeugt. Danach liefert jeder weitere Aufruf mit demselben Namen dieselbe Instanz zurück. Add-ins erhalten Borrowed References — sie dürfen die Instanz nicht freigeben.
user.config.json IWvdSConnectionManager
┌──────────────────┐ ┌─────────────────────────┐
│ "connections": [ │──liest──▶ │ RegisterFactory() │
│ { name, type, │ │ GetConnection() │──▶ Singleton-Provider
│ values } │ │ GetConnectionNames() │
│ ] │ │ CheckInfrastructure() │
└──────────────────┘ │ TestConnection() │
└─────────────────────────┘
Warum zentral?
1. Eine Verbindung, nicht N. Wenn fünf Add-ins jeweils einen eigenen Provider erzeugen, entstehen fünf ODBC-Verbindungen zum selben Server. Die Shell hält pro benannter Verbindung exakt eine Singleton-Instanz. Das reduziert Ressourcenverbrauch und vermeidet Lizenzprobleme bei verbindungslimitierten Datenbanken.
2. Credential-Hoheit. Passwörter und API-Keys liegen in ISecretStorage (DPAPI-geschützt). Die Shell löst sie beim Verbindungsaufbau auf. Kein Add-in erhält jemals Klartext-Credentials — weder zur Laufzeit noch über die Konfigurationsdatei.
3. Einheitliches Verhalten. TrustCertificate, Timeout, Retry-Strategie, Connection-Monitoring: alles einmal in der Shell implementiert, nicht in jedem Add-in dupliziert. Änderungen am Verbindungsverhalten wirken sofort für alle Consumer.
4. Infrastruktur-Check. Die Shell prüft beim Start, ob die benötigten Treiber und Laufzeitumgebungen installiert sind (ODBC Driver 17/18, libsqlite3, TLS-Zertifikate). Das Ergebnis wird in der Settings-Oberfläche angezeigt — der Anwender sieht sofort, ob die Voraussetzungen erfüllt sind.
API
Hilfs-Records
type { Beschreibt ein Konfigurationsfeld eines Providers } TWvdSProviderField = record Name: string; // Feldname, z.B. 'Server', 'Database' TypeName: string; // Typbezeichnung, z.B. 'string', 'boolean', 'integer' Description: string; // Beschreibung für UI/Dokumentation DefaultValue: string; // Standardwert als String end; { Ergebnis einer Infrastrukturprüfung } TWvdSInfraCheckResult = record Available: Boolean; // True wenn der benötigte Treiber vorhanden ist DriverVersion: string; // Erkannte Treiberversion, z.B. '17.10.6.1' Message: string; // Meldung für den Benutzer end; { Ergebnis eines Verbindungstests } TWvdSConnectionTestResult = record Success: Boolean; // True wenn die Verbindung hergestellt werden konnte LatencyMs: Integer; // Antwortzeit in Millisekunden Message: string; // Fehlermeldung oder Statustext end;
IWvdSProviderFactory
Eine Provider-Factory erzeugt Provider-Instanzen für einen bestimmten Typ. Der Host nutzt die Factory, um beim ersten GetConnection-Aufruf den passenden Provider zu erzeugen.
type IWvdSProviderFactory = interface { Gibt den Typ-Bezeichner zurück, z.B. 'mssql', 'rest', 'sqlite' } function GetProviderType: string; { Liefert die Felddefinitionen, die dieser Provider-Typ benötigt. Die Reihenfolge entspricht dem values-Array in der Konfiguration. } function GetConfigFields: TArray<TWvdSProviderField>; { Prüft ob die benötigte Infrastruktur vorhanden ist (z.B. ODBC-Treiber für mssql, libsqlite3 für sqlite). } function CheckInfrastructure: TWvdSInfraCheckResult; { Erzeugt eine Provider-Instanz mit den gegebenen Feldwerten. Die Reihenfolge der Werte entspricht GetConfigFields. } function CreateProvider(const AValues: TStringArray): TObject; end;
| Methode | Beschreibung |
|---|---|
GetProviderType | Gibt den Typ-Bezeichner zurück, z. B. „mssql“, „rest“ oder „sqlite“. Dieser Bezeichner wird in der user.config.json als provider-Feld verwendet. |
GetConfigFields | Liefert die Felddefinitionen, die dieser Provider-Typ benötigt. Für MSSQL sind das Server, Database, TrustedConnection, Encrypt, Timeout. Diese Felddefinitionen werden in der Settings-Oberfläche als Eingabefelder dargestellt. |
CheckInfrastructure | Prüft, ob die Laufzeitumgebung für diesen Provider-Typ vorhanden ist. Bei MSSQL wird geprüft, ob ein ODBC-Treiber (17 oder 18) installiert ist. Das Ergebnis wird beim Shell-Start abgefragt und in der Settings-Oberfläche angezeigt. |
CreateProvider | Erzeugt eine konkrete Provider-Instanz aus den Konfigurationswerten. Das zurückgegebene TObject wird vom Consumer auf den konkreten Typ gecastet (z. B. TWvdSMSSqlProvider). |
IWvdSConnectionManager
Das zentrale Interface, erreichbar über FHost.Connections.
type IWvdSConnectionManager = interface { Registriert eine Factory für einen Provider-Typ. Gibt ein IDisposable zurück — an IExtensionContext übergeben. } function RegisterFactory( AFactory: IWvdSProviderFactory): IDisposable; { Liefert den Provider für eine benannte Verbindung. Erzeugt die Instanz beim ersten Aufruf (Lazy Singleton). Borrowed Reference — NICHT freigeben! } function GetConnection(const AName: string): TObject; { Füllt die Liste mit allen konfigurierten Verbindungsnamen. } procedure GetConnectionNames(AList: TStringList); { Prüft die Infrastruktur für einen Provider-Typ (z.B. ob der ODBC-Treiber installiert ist). } function CheckInfrastructure( const AProviderType: string): TWvdSInfraCheckResult; { Testet eine benannte Verbindung (Aufbau + einfache Query). } function TestConnection( const AName: string): TWvdSConnectionTestResult; end;
| Methode | Beschreibung |
|---|---|
RegisterFactory | Registriert eine Provider-Factory für einen bestimmten Typ. Gibt ein IDisposable zurück, das an IExtensionContext.Subscribe übergeben werden muss. Die Shell registriert die eingebaute mssql-Factory beim Start. Add-ins können eigene Factories nachregistrieren. |
GetConnection | Gibt die Provider-Instanz für die benannte Verbindung zurück. Beim ersten Aufruf wird der Provider über die zuständige Factory erzeugt und gecacht. Weitere Aufrufe liefern dieselbe Instanz (Singleton pro Name). Wichtig: Die zurückgegebene Referenz ist geborgt (Borrowed Reference) — das Add-in darf sie nicht freigeben. Gibt nil zurück, wenn der Name nicht konfiguriert ist. |
GetConnectionNames | Füllt die übergebene TStringList mit den Namen aller konfigurierten Verbindungen. Nützlich für dynamische UI-Elemente (z. B. Verbindungs-Auswahl in einem Dialog). |
CheckInfrastructure | Delegiert an die Factory des angegebenen Provider-Typs und gibt das Infrastruktur-Prüfergebnis zurück. |
TestConnection | Führt einen Verbindungstest für die benannte Verbindung durch. Erzeugt ggf. den Provider, baut die Verbindung auf und misst die Latenz. Das Ergebnis enthält Erfolg/Misserfolg, Latenz in Millisekunden und eine Diagnosemeldung. |
Nutzung im Add-in
Ein Add-in greift über FHost.Connections auf eine konfigurierte Verbindung zu. Der zurückgegebene TObject wird auf den konkreten Provider-Typ gecastet.
var LProvider: TObject; begin LProvider := FHost.Connections.GetConnection('mydb'); if LProvider = nil then begin FHost.Log.Error('Verbindung "mydb" nicht konfiguriert'); Exit; end; // Cast auf den konkreten Provider-Typ TWvdSSQLDBProvider(LProvider).FillWithParams(FDataSet, SSqlExecTree, []); end;
Wichtig: Der Provider ist eine Borrowed Reference. Das Add-in darf Free darauf nicht aufrufen. Der Connection Manager verwaltet den Lebenszyklus — beim Herunterfahren des Hosts werden alle Provider-Instanzen automatisch freigegeben.
Eigene Provider-Factory registrieren
Add-ins können eigene Provider-Typen bereitstellen, indem sie eine IWvdSProviderFactory implementieren und beim Connection Manager registrieren.
type TMyRestFactory = class(TInterfacedObject, IWvdSProviderFactory) public function GetProviderType: string; function GetConfigFields: TArray<TWvdSProviderField>; function CheckInfrastructure: TWvdSInfraCheckResult; function CreateProvider(const AValues: TStringArray): TObject; end; function TMyRestFactory.GetProviderType: string; begin Result := 'rest'; end; function TMyRestFactory.GetConfigFields: TArray<TWvdSProviderField>; begin SetLength(Result, 3); Result[0].Name := 'BaseUrl'; Result[0].TypeName := 'string'; Result[0].Description := 'REST API Basis-URL'; Result[0].DefaultValue := ''; Result[1].Name := 'ApiKey'; Result[1].TypeName := 'string'; Result[1].Description := 'API-Schlüssel'; Result[1].DefaultValue := ''; Result[2].Name := 'Timeout'; Result[2].TypeName := 'integer'; Result[2].Description := 'Timeout in Sekunden'; Result[2].DefaultValue := '30'; end; function TMyRestFactory.CheckInfrastructure: TWvdSInfraCheckResult; begin Result.Available := True; Result.DriverVersion := ''; Result.Message := 'REST-Provider benötigt keine lokale Infrastruktur'; end; function TMyRestFactory.CreateProvider( const AValues: TStringArray): TObject; begin Result := TMyRestProvider.Create( AValues[0], AValues[1], StrToIntDef(AValues[2], 30)); end;
Registrierung im Activate:
procedure TMyPlugin.Activate(const AContext: IExtensionContext); begin AContext.Subscribe( FHost.Connections.RegisterFactory(TMyRestFactory.Create) ); end;
Danach können alle Add-ins Verbindungen vom Typ rest über GetConnection abrufen, sofern eine entsprechende Verbindung in der user.config.json konfiguriert ist.
Konfiguration
Verbindungen werden in der user.config.json (~/.wvdsx/settings.json) im connections-Array konfiguriert. Jeder Eintrag hat drei Felder:
| Feld | Typ | Beschreibung |
|---|---|---|
name | string | Eindeutiger Verbindungsname, über den Add-ins zugreifen |
provider | string | Provider-Typ (muss einer registrierten Factory entsprechen) |
| Weitere Felder | je nach Provider | Benannte Feldwerte gemäß GetConfigFields der zuständigen Factory |
Beispiel: MSSQL-Verbindung
{ "connections": [ { "name": "WIS", "provider": "mssql", "server": "localhost", "database": "WIS", "integratedSecurity": "true", "trustCertificate": "true", "timeout": "30" }, { "name": "archive", "provider": "mssql", "server": "dbserver.local\\INST2", "database": "WIS_ARCHIVE", "integratedSecurity": "false", "trustCertificate": "false", "timeout": "60", "username": "appuser", "password": "secret" } ] }
Die Felder der eingebauten mssql-Factory:
| Feld | Typ | Beschreibung | Default |
|---|---|---|---|
server | string | Servername oder Instanz | localhost |
database | string | Datenbankname / Catalog | (leer) |
integratedSecurity | boolean | Windows-Authentifizierung | true |
trustCertificate | boolean | Serverzertifikat vertrauen | true |
timeout | integer | Verbindungs-Timeout in Sekunden | 30 |
username | string | SQL-Login (nur bei integratedSecurity=false) | (leer) |
password | secret | SQL-Passwort | (leer) |
Infrastruktur-Prüfung
Bevor eine Verbindung hergestellt wird, kann ein Add-in prüfen, ob die benötigte Infrastruktur vorhanden ist. Für mssql prüft der Host, ob ODBC Driver 17 oder 18 installiert ist.
procedure TWISPlugin.CheckDrivers; var LResult: TWvdSInfraCheckResult; begin LResult := FHost.Connections.CheckInfrastructure('mssql'); if LResult.Available then FHost.Log.Info('MSSQL-Treiber verfügbar: ' + LResult.DriverVersion) else begin FHost.Log.Error('MSSQL-Treiber fehlt: ' + LResult.Message); FHost.Notifications.ShowError( 'ODBC Driver 17/18 ist nicht installiert. ' + 'Bitte installieren Sie den Microsoft ODBC Driver für SQL Server.'); end; end;
Verbindungstest
Der Verbindungstest geht einen Schritt weiter: Er baut die Verbindung tatsächlich auf und misst die Antwortzeit.
procedure TWISPlugin.TestWISConnection; var LResult: TWvdSConnectionTestResult; begin LResult := FHost.Connections.TestConnection('wis'); if LResult.Success then FHost.Log.Info(Format('Verbindung "wis" erfolgreich (%d ms)', [LResult.LatencyMs])) else FHost.Log.Error('Verbindung "wis" fehlgeschlagen: ' + LResult.Message); end;
Fehlerbehandlung
| Situation | Verhalten |
|---|---|
Verbindungsname nicht in user.config.json | GetConnection gibt nil zurück |
| Provider-Typ ohne registrierte Factory | GetConnection gibt nil zurück, Log-Eintrag auf Error-Level |
| Infrastruktur fehlt (z.B. ODBC-Treiber) | CheckInfrastructure gibt Available = False zurück |
| Verbindungsaufbau schlägt fehl | TestConnection gibt Success = False mit Fehlermeldung zurück |
| Factory-Registrierung für existierenden Typ | Überschreibt die bestehende Factory (letzte Registrierung gewinnt) |
Weiter zur Service-Referenz oder zurück zur SDK-Übersicht.