diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
index a2dd97db..198813e8 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
@@ -353,10 +353,123 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
connectionBuilder["Integrated Security"] = false;
connectionBuilder["User Id"] = connectionDetails.UserName;
connectionBuilder["Password"] = connectionDetails.Password;
- if( !String.IsNullOrEmpty(connectionDetails.DatabaseName) )
+
+ // Check for any optional parameters
+ if (!String.IsNullOrEmpty(connectionDetails.DatabaseName))
{
connectionBuilder["Initial Catalog"] = connectionDetails.DatabaseName;
}
+ if (!String.IsNullOrEmpty(connectionDetails.AuthenticationType))
+ {
+ switch(connectionDetails.AuthenticationType)
+ {
+ case "Integrated":
+ connectionBuilder.IntegratedSecurity = true;
+ break;
+ case "SqlLogin":
+ connectionBuilder.IntegratedSecurity = false;
+ break;
+ default:
+ throw new ArgumentException("Invalid value \"" + connectionDetails.AuthenticationType + "\" for AuthenticationType. Valid values are \"Integrated\" and \"SqlLogin\".");
+ }
+ }
+ if (connectionDetails.Encrypt.HasValue)
+ {
+ connectionBuilder.Encrypt = connectionDetails.Encrypt.Value;
+ }
+ if (connectionDetails.TrustServerCertificate.HasValue)
+ {
+ connectionBuilder.TrustServerCertificate = connectionDetails.TrustServerCertificate.Value;
+ }
+ if (connectionDetails.PersistSecurityInfo.HasValue)
+ {
+ connectionBuilder.PersistSecurityInfo = connectionDetails.PersistSecurityInfo.Value;
+ }
+ if (connectionDetails.ConnectTimeout.HasValue)
+ {
+ connectionBuilder.ConnectTimeout = connectionDetails.ConnectTimeout.Value;
+ }
+ if (connectionDetails.ConnectRetryCount.HasValue)
+ {
+ connectionBuilder.ConnectRetryCount = connectionDetails.ConnectRetryCount.Value;
+ }
+ if (connectionDetails.ConnectRetryInterval.HasValue)
+ {
+ connectionBuilder.ConnectRetryInterval = connectionDetails.ConnectRetryInterval.Value;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.ApplicationName))
+ {
+ connectionBuilder.ApplicationName = connectionDetails.ApplicationName;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.WorkstationId))
+ {
+ connectionBuilder.WorkstationID = connectionDetails.WorkstationId;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.ApplicationIntent))
+ {
+ ApplicationIntent intent;
+ switch (connectionDetails.ApplicationIntent)
+ {
+ case "ReadOnly":
+ intent = ApplicationIntent.ReadOnly;
+ break;
+ case "ReadWrite":
+ intent = ApplicationIntent.ReadWrite;
+ break;
+ default:
+ throw new ArgumentException("Invalid value \"" + connectionDetails.ApplicationIntent + "\" for ApplicationIntent. Valid values are \"ReadWrite\" and \"ReadOnly\".");
+ }
+ connectionBuilder.ApplicationIntent = intent;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.CurrentLanguage))
+ {
+ connectionBuilder.CurrentLanguage = connectionDetails.CurrentLanguage;
+ }
+ if (connectionDetails.Pooling.HasValue)
+ {
+ connectionBuilder.Pooling = connectionDetails.Pooling.Value;
+ }
+ if (connectionDetails.MaxPoolSize.HasValue)
+ {
+ connectionBuilder.MaxPoolSize = connectionDetails.MaxPoolSize.Value;
+ }
+ if (connectionDetails.MinPoolSize.HasValue)
+ {
+ connectionBuilder.MinPoolSize = connectionDetails.MinPoolSize.Value;
+ }
+ if (connectionDetails.LoadBalanceTimeout.HasValue)
+ {
+ connectionBuilder.LoadBalanceTimeout = connectionDetails.LoadBalanceTimeout.Value;
+ }
+ if (connectionDetails.Replication.HasValue)
+ {
+ connectionBuilder.Replication = connectionDetails.Replication.Value;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.AttachDbFilename))
+ {
+ connectionBuilder.AttachDBFilename = connectionDetails.AttachDbFilename;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.FailoverPartner))
+ {
+ connectionBuilder.FailoverPartner = connectionDetails.FailoverPartner;
+ }
+ if (connectionDetails.MultiSubnetFailover.HasValue)
+ {
+ connectionBuilder.MultiSubnetFailover = connectionDetails.MultiSubnetFailover.Value;
+ }
+ if (connectionDetails.MultipleActiveResultSets.HasValue)
+ {
+ connectionBuilder.MultipleActiveResultSets = connectionDetails.MultipleActiveResultSets.Value;
+ }
+ if (connectionDetails.PacketSize.HasValue)
+ {
+ connectionBuilder.PacketSize = connectionDetails.PacketSize.Value;
+ }
+ if (!String.IsNullOrEmpty(connectionDetails.TypeSystemVersion))
+ {
+ connectionBuilder.TypeSystemVersion = connectionDetails.TypeSystemVersion;
+ }
+
return connectionBuilder.ToString();
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs
index 0acac867..ce1c6208 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs
@@ -8,6 +8,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
///
/// Message format for the initial connection request
///
+ ///
+ /// If this contract is ever changed, be sure to update ConnectionDetailsExtensions methods.
+ ///
public class ConnectionDetails : ConnectionSummary
{
///
@@ -16,6 +19,114 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
///
public string Password { get; set; }
- // TODO Handle full set of properties
+ ///
+ /// Gets or sets the authentication to use.
+ ///
+ public string AuthenticationType { get; set; }
+
+ ///
+ /// Gets or sets a Boolean value that indicates whether SQL Server uses SSL encryption for all data sent between the client and server if the server has a certificate installed.
+ ///
+ public bool? Encrypt { get; set; }
+
+ ///
+ /// Gets or sets a value that indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust.
+ ///
+ public bool? TrustServerCertificate { get; set; }
+
+ ///
+ /// Gets or sets a Boolean value that indicates if security-sensitive information, such as the password, is not returned as part of the connection if the connection is open or has ever been in an open state.
+ ///
+ public bool? PersistSecurityInfo { get; set; }
+
+ ///
+ /// Gets or sets the length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.
+ ///
+ public int? ConnectTimeout { get; set; }
+
+ ///
+ /// The number of reconnections attempted after identifying that there was an idle connection failure.
+ ///
+ public int? ConnectRetryCount { get; set; }
+
+ ///
+ /// Amount of time (in seconds) between each reconnection attempt after identifying that there was an idle connection failure.
+ ///
+ public int? ConnectRetryInterval { get; set; }
+
+ ///
+ /// Gets or sets the name of the application associated with the connection string.
+ ///
+ public string ApplicationName { get; set; }
+
+ ///
+ /// Gets or sets the name of the workstation connecting to SQL Server.
+ ///
+ public string WorkstationId { get; set; }
+
+ ///
+ /// Declares the application workload type when connecting to a database in an SQL Server Availability Group.
+ ///
+ public string ApplicationIntent { get; set; }
+
+ ///
+ /// Gets or sets the SQL Server Language record name.
+ ///
+ public string CurrentLanguage { get; set; }
+
+ ///
+ /// Gets or sets a Boolean value that indicates whether the connection will be pooled or explicitly opened every time that the connection is requested.
+ ///
+ public bool? Pooling { get; set; }
+
+ ///
+ /// Gets or sets the maximum number of connections allowed in the connection pool for this specific connection string.
+ ///
+ public int? MaxPoolSize { get; set; }
+
+ ///
+ /// Gets or sets the minimum number of connections allowed in the connection pool for this specific connection string.
+ ///
+ public int? MinPoolSize { get; set; }
+
+ ///
+ /// Gets or sets the minimum time, in seconds, for the connection to live in the connection pool before being destroyed.
+ ///
+ public int? LoadBalanceTimeout { get; set; }
+
+ ///
+ /// Gets or sets a Boolean value that indicates whether replication is supported using the connection.
+ ///
+ public bool? Replication { get; set; }
+
+ ///
+ /// Gets or sets a string that contains the name of the primary data file. This includes the full path name of an attachable database.
+ ///
+ public string AttachDbFilename { get; set; }
+
+ ///
+ /// Gets or sets the name or address of the partner server to connect to if the primary server is down.
+ ///
+ public string FailoverPartner { get; set; }
+
+ ///
+ /// If your application is connecting to an AlwaysOn availability group (AG) on different subnets, setting MultiSubnetFailover=true provides faster detection of and connection to the (currently) active server.
+ ///
+ public bool? MultiSubnetFailover { get; set; }
+
+ ///
+ /// When true, an application can maintain multiple active result sets (MARS).
+ ///
+ public bool? MultipleActiveResultSets { get; set; }
+
+ ///
+ /// Gets or sets the size in bytes of the network packets used to communicate with an instance of SQL Server.
+ ///
+ public int? PacketSize { get; set; }
+
+ ///
+ /// Gets or sets a string value that indicates the type system the application expects.
+ ///
+ public string TypeSystemVersion { get; set; }
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs
index de278dbc..106fa06e 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs
@@ -20,7 +20,29 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
ServerName = details.ServerName,
DatabaseName = details.DatabaseName,
UserName = details.UserName,
- Password = details.Password
+ Password = details.Password,
+ AuthenticationType = details.AuthenticationType,
+ Encrypt = details.Encrypt,
+ TrustServerCertificate = details.TrustServerCertificate,
+ PersistSecurityInfo = details.PersistSecurityInfo,
+ ConnectTimeout = details.ConnectTimeout,
+ ConnectRetryCount = details.ConnectRetryCount,
+ ConnectRetryInterval = details.ConnectRetryInterval,
+ ApplicationName = details.ApplicationName,
+ WorkstationId = details.WorkstationId,
+ ApplicationIntent = details.ApplicationIntent,
+ CurrentLanguage = details.CurrentLanguage,
+ Pooling = details.Pooling,
+ MaxPoolSize = details.MaxPoolSize,
+ MinPoolSize = details.MinPoolSize,
+ LoadBalanceTimeout = details.LoadBalanceTimeout,
+ Replication = details.Replication,
+ AttachDbFilename = details.AttachDbFilename,
+ FailoverPartner = details.FailoverPartner,
+ MultiSubnetFailover = details.MultiSubnetFailover,
+ MultipleActiveResultSets = details.MultipleActiveResultSets,
+ PacketSize = details.PacketSize,
+ TypeSystemVersion = details.TypeSystemVersion
};
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs
index b6888b0a..1c3cc8d9 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs
@@ -7,10 +7,10 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
+using System.Reflection;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
-using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
using Microsoft.SqlTools.Test.Utility;
using Moq;
@@ -197,6 +197,54 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection
Assert.NotEqual(String.Empty, connectionResult.Messages);
}
+ ///
+ /// Verify that optional parameters can be built into a connection string for connecting.
+ ///
+ [Theory]
+ [InlineDataAttribute("AuthenticationType", "Integrated")]
+ [InlineDataAttribute("AuthenticationType", "SqlLogin")]
+ [InlineDataAttribute("Encrypt", true)]
+ [InlineDataAttribute("Encrypt", false)]
+ [InlineDataAttribute("TrustServerCertificate", true)]
+ [InlineDataAttribute("TrustServerCertificate", false)]
+ [InlineDataAttribute("PersistSecurityInfo", true)]
+ [InlineDataAttribute("PersistSecurityInfo", false)]
+ [InlineDataAttribute("ConnectTimeout", 15)]
+ [InlineDataAttribute("ConnectRetryCount", 1)]
+ [InlineDataAttribute("ConnectRetryInterval", 10)]
+ [InlineDataAttribute("ApplicationName", "vscode-mssql")]
+ [InlineDataAttribute("WorkstationId", "mycomputer")]
+ [InlineDataAttribute("ApplicationIntent", "ReadWrite")]
+ [InlineDataAttribute("ApplicationIntent", "ReadOnly")]
+ [InlineDataAttribute("CurrentLanguage", "test")]
+ [InlineDataAttribute("Pooling", false)]
+ [InlineDataAttribute("Pooling", true)]
+ [InlineDataAttribute("MaxPoolSize", 100)]
+ [InlineDataAttribute("MinPoolSize", 0)]
+ [InlineDataAttribute("LoadBalanceTimeout", 0)]
+ [InlineDataAttribute("Replication", true)]
+ [InlineDataAttribute("Replication", false)]
+ [InlineDataAttribute("AttachDbFilename", "myfile")]
+ [InlineDataAttribute("FailoverPartner", "partner")]
+ [InlineDataAttribute("MultiSubnetFailover", true)]
+ [InlineDataAttribute("MultiSubnetFailover", false)]
+ [InlineDataAttribute("MultipleActiveResultSets", false)]
+ [InlineDataAttribute("MultipleActiveResultSets", true)]
+ [InlineDataAttribute("PacketSize", 8192)]
+ [InlineDataAttribute("TypeSystemVersion", "Latest")]
+ public void ConnectingWithOptionalParametersBuildsConnectionString(string propertyName, object propertyValue)
+ {
+ // Create a test connection details object and set the property to a specific value
+ ConnectionDetails details = TestObjects.GetTestConnectionDetails();
+ PropertyInfo info = details.GetType().GetProperty(propertyName);
+ info.SetValue(details, propertyValue);
+
+ // Test that a connection string can be created without exceptions
+ string connectionString = ConnectionService.BuildConnectionString(details);
+ Assert.NotNull(connectionString);
+ Assert.NotEmpty(connectionString);
+ }
+
///
/// Verify that the SQL parser correctly detects errors in text
///