From ffc3a97a758c712ffd1629548bdf495f706fa84f Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 29 Apr 2026 19:22:06 +0100 Subject: [PATCH 1/2] implements [FEATURE] Allow Read-only intent (for AG listeners and readable replicas - including Query Store on secondary replicas) Fixes #301 --- .../Dialogs/ConnectionDialog.axaml | 25 +++++++++++++------ .../Dialogs/ConnectionDialog.axaml.cs | 9 +++++-- .../Services/ConnectionStore.cs | 1 + .../Models/ServerConnection.cs | 6 ++++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml b/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml index ed2d3d8..e9fc75e 100644 --- a/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml +++ b/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml @@ -68,14 +68,23 @@ - - - - - - - + + + + + + + + + + + + diff --git a/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml.cs b/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml.cs index 3a112ab..5603b3b 100644 --- a/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml.cs +++ b/src/PlanViewer.App/Dialogs/ConnectionDialog.axaml.cs @@ -78,6 +78,7 @@ private void ApplySavedConnection(ServerConnection saved) } TrustCertBox.IsChecked = saved.TrustServerCertificate; + ReadOnlyIntentCheckBox.IsChecked = saved.ApplicationIntentReadOnly; // Load stored credentials var cred = _credentialService.GetCredential(saved.Id); @@ -217,7 +218,8 @@ private ServerConnection BuildServerConnection() DisplayName = serverName, AuthenticationType = GetSelectedAuthType(), TrustServerCertificate = TrustCertBox.IsChecked == true, - EncryptMode = GetSelectedEncryptMode() + EncryptMode = GetSelectedEncryptMode(), + ApplicationIntentReadOnly = ReadOnlyIntentCheckBox.IsChecked == true }; } @@ -249,7 +251,10 @@ private string BuildConnectionString(ServerConnection connection) "Optional" => SqlConnectionEncryptOption.Optional, "Strict" => SqlConnectionEncryptOption.Strict, _ => SqlConnectionEncryptOption.Mandatory - } + }, + ApplicationIntent = connection.ApplicationIntentReadOnly + ? ApplicationIntent.ReadOnly + : ApplicationIntent.ReadWrite }; switch (connection.AuthenticationType) diff --git a/src/PlanViewer.App/Services/ConnectionStore.cs b/src/PlanViewer.App/Services/ConnectionStore.cs index 9d0e8b9..edeb8b8 100644 --- a/src/PlanViewer.App/Services/ConnectionStore.cs +++ b/src/PlanViewer.App/Services/ConnectionStore.cs @@ -53,6 +53,7 @@ public void AddOrUpdate(ServerConnection connection) existing.AuthenticationType = connection.AuthenticationType; existing.EncryptMode = connection.EncryptMode; existing.TrustServerCertificate = connection.TrustServerCertificate; + existing.ApplicationIntentReadOnly = connection.ApplicationIntentReadOnly; existing.DisplayName = connection.DisplayName; existing.LastConnected = DateTime.Now; } diff --git a/src/PlanViewer.Core/Models/ServerConnection.cs b/src/PlanViewer.Core/Models/ServerConnection.cs index 7b3c420..b21c073 100644 --- a/src/PlanViewer.Core/Models/ServerConnection.cs +++ b/src/PlanViewer.Core/Models/ServerConnection.cs @@ -16,6 +16,7 @@ public class ServerConnection public bool IsFavorite { get; set; } public string EncryptMode { get; set; } = "Mandatory"; public bool TrustServerCertificate { get; set; } = false; + public bool ApplicationIntentReadOnly { get; set; } = false; [JsonIgnore] public string AuthenticationDisplay => AuthenticationType switch @@ -39,7 +40,10 @@ public string GetConnectionString(ICredentialService credentialService, string? "Optional" => SqlConnectionEncryptOption.Optional, "Strict" => SqlConnectionEncryptOption.Strict, _ => SqlConnectionEncryptOption.Mandatory - } + }, + ApplicationIntent = ApplicationIntentReadOnly + ? ApplicationIntent.ReadOnly + : ApplicationIntent.ReadWrite }; if (!string.IsNullOrEmpty(databaseName)) From 292a5ba0f6a9dea49f4035a2bcd5b4b0cf2b7717 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 29 Apr 2026 19:23:00 +0100 Subject: [PATCH 2/2] Add visual info that we are connected to a secondary. #301 --- src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs b/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs index 78ab33a..420a9a4 100644 --- a/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs +++ b/src/PlanViewer.App/Controls/QuerySessionControl.axaml.cs @@ -809,7 +809,9 @@ private async Task ShowConnectionDialogAsync() _selectedDatabase = dialog.ResultDatabase; _connectionString = _serverConnection.GetConnectionString(_credentialService, _selectedDatabase); - ServerLabel.Text = _serverConnection.ServerName; + ServerLabel.Text = _serverConnection.ApplicationIntentReadOnly + ? $"{_serverConnection.ServerName} (Secondary)" + : _serverConnection.ServerName; ServerLabel.Foreground = Brushes.LimeGreen; ConnectButton.Content = "Reconnect";