diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
index 63c4da66..f09e39a9 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
@@ -29,6 +29,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
///
public class ConnectionService
{
+ public const string AdminConnectionPrefix = "ADMIN:";
+
///
/// Singleton service instance
///
@@ -444,6 +446,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
throw new InvalidOperationException(SR.ConnectionServiceDbErrorDefaultNotConnected(ownerUri));
}
+ if(IsDedicatedAdminConnection(connectionInfo.ConnectionDetails))
+ {
+ // Since this is a dedicated connection only 1 is allowed at any time. Return the default connection for use in the requested action
+ return defaultConnection;
+ }
+
// Try to get the DbConnection
DbConnection connection;
if (!connectionInfo.TryGetConnection(connectionType, out connection) && ConnectionType.Default != connectionType)
@@ -842,12 +850,33 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
await requestContext.SendError(ex.ToString());
}
}
-
+
+ ///
+ /// Checks if a ConnectionDetails object represents a DAC connection
+ ///
+ ///
+ public static bool IsDedicatedAdminConnection(ConnectionDetails connectionDetails)
+ {
+ Validate.IsNotNull(nameof(connectionDetails), connectionDetails);
+ SqlConnectionStringBuilder builder = CreateConnectionStringBuilder(connectionDetails);
+ string serverName = builder.DataSource;
+ return serverName != null && serverName.StartsWith(AdminConnectionPrefix, StringComparison.OrdinalIgnoreCase);
+ }
+
///
/// Build a connection string from a connection details instance
///
///
public static string BuildConnectionString(ConnectionDetails connectionDetails)
+ {
+ return CreateConnectionStringBuilder(connectionDetails).ToString();
+ }
+
+ ///
+ /// Build a connection string builder a connection details instance
+ ///
+ ///
+ public static SqlConnectionStringBuilder CreateConnectionStringBuilder(ConnectionDetails connectionDetails)
{
SqlConnectionStringBuilder connectionBuilder;
@@ -981,7 +1010,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
connectionBuilder.TypeSystemVersion = connectionDetails.TypeSystemVersion;
}
- return connectionBuilder.ToString();
+ return connectionBuilder;
}
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs
index 3c1d1dee..61177c09 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs
@@ -834,6 +834,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
await Task.Run(() =>
{
+ if (ConnectionService.IsDedicatedAdminConnection(info.ConnectionDetails))
+ {
+ // Intellisense cannot be run on these connections as only 1 SqlConnection can be opened on them at a time
+ return;
+ }
ScriptParseInfo scriptInfo = GetScriptParseInfo(info.OwnerUri, createIfNotExists: true);
if (Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout))
{
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Connection/ConnectionServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Connection/ConnectionServiceTests.cs
index 9171d7cf..db82dba7 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Connection/ConnectionServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Connection/ConnectionServiceTests.cs
@@ -1210,6 +1210,48 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Connection
await Assert.ThrowsAsync(
() => service.GetOrOpenConnection(TestObjects.ScriptUri, ConnectionType.Query));
}
+
+ [Fact]
+ public async Task GetOrOpenAdminDefaultConnection()
+ {
+ // Setup: Create a connection service with an empty connection info obj
+ var service = TestObjects.GetTestConnectionService();
+ var connInfo = new ConnectionInfo(null, null, null);
+ service.OwnerToConnectionMap[TestObjects.ScriptUri] = connInfo;
+
+ // If: I ask for a connection on a connection that doesn't have a default connection
+ // Then: An exception should be thrown
+ await Assert.ThrowsAsync(
+ () => service.GetOrOpenConnection(TestObjects.ScriptUri, ConnectionType.Query));
+ }
+
+ [Fact]
+ public async Task ConnectionWithAdminConnectionEnsuresOnlyOneConnectionCreated()
+ {
+ // If I try to connect using a connection string, it overrides the server name and username for the connection
+ ConnectParams connectionParameters = TestObjects.GetTestConnectionParams();
+ string serverName = "ADMIN:overriddenServerName";
+ string userName = "overriddenUserName";
+ connectionParameters.Connection.ServerName = serverName;
+ connectionParameters.Connection.UserName = userName;
+
+ // Connect
+ ConnectionService service = TestObjects.GetTestConnectionService();
+ var connectionResult = await service.Connect(connectionParameters);
+
+ // Verify you can get the connection for default
+ DbConnection defaultConn = await service.GetOrOpenConnection(connectionParameters.OwnerUri, ConnectionType.Default);
+ ConnectionInfo connInfo = service.OwnerToConnectionMap[connectionParameters.OwnerUri];
+ Assert.NotNull(defaultConn);
+ Assert.Equal(connInfo.AllConnections.Count, 1);
+
+ // Verify that for the Query, no new connection is created
+ DbConnection queryConn = await service.GetOrOpenConnection(connectionParameters.OwnerUri, ConnectionType.Query);
+ connInfo = service.OwnerToConnectionMap[connectionParameters.OwnerUri];
+ Assert.NotNull(defaultConn);
+ Assert.Equal(connInfo.AllConnections.Count, 1);
+
+ }
[Fact]
public async Task ConnectionWithConnectionStringSucceeds()