diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index c35899a762..b56e1be1b6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -53,12 +53,30 @@ Microsoft\Data\Common\BitConverterCompatible.cs + + Microsoft\Data\Common\ConnectionString\AttestationProtocolUtilities.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringDefaults.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringKeywords.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringSynonyms.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringUtilities.cs + + + Microsoft\Data\Common\ConnectionString\IpAddressPreferenceUtilities.cs + + + Microsoft\Data\Common\ConnectionString\PoolBlockingUtilities.cs + Microsoft\Data\Common\DbConnectionOptions.Common.cs - - Microsoft\Data\Common\DbConnectionStringCommon.cs - Microsoft\Data\Common\MultipartIdentifier.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs index 759696d471..443b7e6734 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Text; +using Microsoft.Data.Common.ConnectionString; namespace Microsoft.Data.Common { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs index 56835611de..bb568f1f9d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -194,19 +194,19 @@ public SqlConnection(string connectionString, SqlCredential credential) : this() } else if (UsesActiveDirectoryManagedIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } else if (UsesActiveDirectoryMSI(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryMSIString); } else if (UsesActiveDirectoryDefault(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } else if (UsesActiveDirectoryWorkloadIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } Credential = credential; @@ -621,19 +621,19 @@ public override string ConnectionString } else if (UsesActiveDirectoryManagedIdentity(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } else if (UsesActiveDirectoryMSI(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryMSIString); } else if (UsesActiveDirectoryDefault(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } else if (UsesActiveDirectoryWorkloadIdentity(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions); @@ -1005,19 +1005,19 @@ public SqlCredential Credential } else if (UsesActiveDirectoryManagedIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } else if (UsesActiveDirectoryMSI(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryMSIString); } else if (UsesActiveDirectoryDefault(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } else if (UsesActiveDirectoryWorkloadIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 20f02e7204..415b3825e0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -234,8 +234,26 @@ Microsoft\Data\Common\BitConverterCompatible.cs - - Microsoft\Data\Common\DbConnectionStringCommon.cs + + Microsoft\Data\Common\ConnectionString\AttestationProtocolUtilities.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringDefaults.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringKeywords.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringSynonyms.cs + + + Microsoft\Data\Common\ConnectionString\DbConnectionStringUtilities.cs + + + Microsoft\Data\Common\ConnectionString\IpAddressPreferenceUtilities.cs + + + Microsoft\Data\Common\ConnectionString\PoolBlockingUtilities.cs Microsoft\Data\Common\DbConnectionOptions.Common.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs index 66c46602c5..4fe523ae2f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs @@ -2,16 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Text; +using Microsoft.Data.Common.ConnectionString; +using Microsoft.Data.SqlClient; + namespace Microsoft.Data.Common { - - using System; - using System.Collections.Generic; - using System.Data; - using System.Diagnostics; - using System.Text; - using Microsoft.Data.SqlClient; - [Serializable] // MDAC 83147 internal sealed class DBConnectionString { @@ -19,6 +19,7 @@ internal sealed class DBConnectionString // used by permission classes so it is much easier to verify correctness // when not worried about the class being modified during execution + // @TODO: Remove in favor of DbConnectionStringKeywords private static class KEY { internal const string Password = DbConnectionStringKeywords.Password; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs index e240c3d822..b0507ea83e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs @@ -6,6 +6,7 @@ using System.Runtime.Versioning; using System.Security; using System.Text; +using Microsoft.Data.Common.ConnectionString; namespace Microsoft.Data.Common { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs index c141793e1b..8a61bf7b8e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -388,22 +388,22 @@ public SqlConnection(string connectionString, SqlCredential credential) : this() if (UsesActiveDirectoryManagedIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } if (UsesActiveDirectoryMSI(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryMSIString); } if (UsesActiveDirectoryDefault(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } if (UsesActiveDirectoryWorkloadIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.SettingCredentialWithNonInteractiveArgument(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } Credential = credential; @@ -823,19 +823,19 @@ override public string ConnectionString } else if (UsesActiveDirectoryManagedIdentity(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } else if (UsesActiveDirectoryMSI(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryMSIString); } else if (UsesActiveDirectoryDefault(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } else if (UsesActiveDirectoryWorkloadIdentity(connectionOptions)) { - throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.SettingNonInteractiveWithCredential(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions); @@ -1176,19 +1176,19 @@ public SqlCredential Credential } else if (UsesActiveDirectoryManagedIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } else if (UsesActiveDirectoryMSI(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryMSIString); } else if (UsesActiveDirectoryDefault(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } else if (UsesActiveDirectoryWorkloadIdentity(connectionOptions)) { - throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.SettingCredentialWithNonInteractiveInvalid(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index f51723ace2..c8dcdd6934 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -18,6 +18,7 @@ using System.Threading; using System.Threading.Tasks; using System.Transactions; +using Microsoft.Data.Common.ConnectionString; using Microsoft.Data.SqlClient; using IsolationLevel = System.Data.IsolationLevel; using Microsoft.Identity.Client; @@ -47,6 +48,7 @@ internal static partial class ADP { // NOTE: Initializing a Task in SQL CLR requires the "UNSAFE" permission set (http://msdn.microsoft.com/en-us/library/ms172338.aspx) // Therefore we are lazily initializing these Tasks to avoid forcing customers to use the "UNSAFE" set when they are actually using no Async features + // @TODO: These are not necessary because the TPL has optimized commonly used task return values like true and false. private static Task s_trueTask; internal static Task TrueTask => s_trueTask ??= Task.FromResult(true); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/AttestationProtocolUtilities.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/AttestationProtocolUtilities.cs new file mode 100644 index 0000000000..75e6eede3f --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/AttestationProtocolUtilities.cs @@ -0,0 +1,148 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using Microsoft.Data.SqlClient; + +namespace Microsoft.Data.Common.ConnectionString +{ + internal static class AttestationProtocolUtilities + { + /// + /// Convert a string value to the corresponding SqlConnectionAttestationProtocol + /// + /// + /// + /// + internal static bool TryConvertToAttestationProtocol(string value, out SqlConnectionAttestationProtocol result) + { + if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.HGS))) + { + result = SqlConnectionAttestationProtocol.HGS; + return true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.AAS))) + { + result = SqlConnectionAttestationProtocol.AAS; + return true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.None))) + { + result = SqlConnectionAttestationProtocol.None; + return true; + } + else + { + result = DbConnectionStringDefaults.AttestationProtocol; + return false; + } + } + + internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) + { + Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); + return value == SqlConnectionAttestationProtocol.NotSpecified + || value == SqlConnectionAttestationProtocol.HGS + || value == SqlConnectionAttestationProtocol.AAS + || value == SqlConnectionAttestationProtocol.None; + } + + internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) + { + Debug.Assert(IsValidAttestationProtocol(value), "value is not a valid attestation protocol"); + + return value switch + { + SqlConnectionAttestationProtocol.AAS => nameof(SqlConnectionAttestationProtocol.AAS), + SqlConnectionAttestationProtocol.HGS => nameof(SqlConnectionAttestationProtocol.HGS), + SqlConnectionAttestationProtocol.None => nameof(SqlConnectionAttestationProtocol.None), + _ => null + }; + } + + internal static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(string keyword, object value) + { + if (value == null) + { + return DbConnectionStringDefaults.AttestationProtocol; + } + + if (value is string sValue) + { + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToAttestationProtocol(sValue, out SqlConnectionAttestationProtocol result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + SqlConnectionAttestationProtocol eValue; + + if (value is SqlConnectionAttestationProtocol protocol) + { + eValue = protocol; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["SqlConnectionAttestationProtocol"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-SqlConnectionAttestationProtocol enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (SqlConnectionAttestationProtocol)Enum.ToObject(typeof(SqlConnectionAttestationProtocol), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), e); + } + } + + if (IsValidAttestationProtocol(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(SqlConnectionAttestationProtocol), (int)eValue); + } + } + } + + internal static SqlConnectionEncryptOption ConvertToSqlConnectionEncryptOption(string keyword, object value) + { + if (value is null) + { + return DbConnectionStringDefaults.Encrypt; + } + else if(value is SqlConnectionEncryptOption eValue) + { + return eValue; + } + else if (value is string sValue) + { + return SqlConnectionEncryptOption.Parse(sValue); + } + else if(value is bool bValue) + { + return SqlConnectionEncryptOption.Parse(bValue); + } + + throw ADP.InvalidConnectionOptionValue(keyword); + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringDefaults.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringDefaults.cs new file mode 100644 index 0000000000..de3971a1e4 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringDefaults.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Data.SqlClient; + +namespace Microsoft.Data.Common.ConnectionString +{ + internal static class DbConnectionStringDefaults + { + internal const ApplicationIntent ApplicationIntent = Microsoft.Data.SqlClient.ApplicationIntent.ReadWrite; + internal const string ApplicationName = + #if NETFRAMEWORK + "Framework Microsoft SqlClient Data Provider"; + #else + "Core Microsoft SqlClient Data Provider"; + #endif + internal const string AttachDBFilename = ""; + internal const SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; + internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified; + internal const SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; + internal const int CommandTimeout = 30; + internal const int ConnectRetryCount = 1; + internal const int ConnectRetryInterval = 10; + internal const int ConnectTimeout = 15; + internal const bool ContextConnection = false; + internal const string CurrentLanguage = ""; + internal const string DataSource = ""; + internal const string EnclaveAttestationUrl = ""; + internal static readonly SqlConnectionEncryptOption Encrypt = SqlConnectionEncryptOption.Mandatory; + internal const bool Enlist = true; + internal const string FailoverPartner = ""; + internal const string FailoverPartnerSPN = ""; + internal const string HostNameInCertificate = ""; + internal const string InitialCatalog = ""; + internal const bool IntegratedSecurity = false; + internal const SqlConnectionIPAddressPreference IPAddressPreference = SqlConnectionIPAddressPreference.IPv4First; + internal const int LoadBalanceTimeout = 0; // default of 0 means don't use + internal const int MaxPoolSize = 100; + internal const int MinPoolSize = 0; + internal const bool MultipleActiveResultSets = false; + internal const bool MultiSubnetFailover = false; + internal const int PacketSize = 8000; + internal const string Password = ""; + internal const bool PersistSecurityInfo = false; + internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto; + internal const bool Pooling = true; + internal const bool Replication = false; + internal const string ServerCertificate = ""; + internal const string ServerSPN = ""; + internal const string TransactionBinding = "Implicit Unbind"; + internal const bool TrustServerCertificate = false; + internal const string TypeSystemVersion = "Latest"; + internal const string UserID = ""; + internal const bool UserInstance = false; + internal const string WorkstationID = ""; + + #if NETFRAMEWORK + internal const bool ConnectionReset = true; + internal static readonly bool TransparentNetworkIPResolution = !LocalAppContextSwitches.DisableTNIRByDefault; + internal const string NetworkLibrary = ""; + #endif + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringKeywords.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringKeywords.cs new file mode 100644 index 0000000000..65cb781fa1 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringKeywords.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Data.Common.ConnectionString +{ + internal static class DbConnectionStringKeywords + { + // SqlClient + internal const string ApplicationIntent = "Application Intent"; + internal const string ApplicationName = "Application Name"; + internal const string AttachDBFilename = "AttachDbFilename"; + internal const string AttestationProtocol = "Attestation Protocol"; + internal const string Authentication = "Authentication"; + internal const string ColumnEncryptionSetting = "Column Encryption Setting"; + internal const string CommandTimeout = "Command Timeout"; + internal const string ConnectionReset = "Connection Reset"; + internal const string ConnectRetryCount = "Connect Retry Count"; + internal const string ConnectRetryInterval = "Connect Retry Interval"; + internal const string ConnectTimeout = "Connect Timeout"; + internal const string ContextConnection = "Context Connection"; + internal const string CurrentLanguage = "Current Language"; + internal const string DataSource = "Data Source"; + internal const string EnclaveAttestationUrl = "Enclave Attestation Url"; + internal const string Encrypt = "Encrypt"; + internal const string Enlist = "Enlist"; + internal const string FailoverPartner = "Failover Partner"; + internal const string FailoverPartnerSPN = "Failover Partner SPN"; + internal const string HostNameInCertificate = "Host Name In Certificate"; + internal const string InitialCatalog = "Initial Catalog"; + internal const string IntegratedSecurity = "Integrated Security"; + internal const string IPAddressPreference = "IP Address Preference"; + internal const string LoadBalanceTimeout = "Load Balance Timeout"; + internal const string MaxPoolSize = "Max Pool Size"; + internal const string MinPoolSize = "Min Pool Size"; + internal const string MultipleActiveResultSets = "Multiple Active Result Sets"; + internal const string MultiSubnetFailover = "Multi Subnet Failover"; + internal const string NetworkLibrary = "Network Library"; + internal const string PacketSize = "Packet Size"; + internal const string Password = "Password"; + internal const string PersistSecurityInfo = "Persist Security Info"; + internal const string PoolBlockingPeriod = "Pool Blocking Period"; + internal const string Pooling = "Pooling"; + internal const string Replication = "Replication"; + internal const string ServerCertificate = "Server Certificate"; + internal const string ServerSPN = "Server SPN"; + internal const string TransactionBinding = "Transaction Binding"; + internal const string TransparentNetworkIPResolution = "Transparent Network IP Resolution"; + internal const string TrustServerCertificate = "Trust Server Certificate"; + internal const string TypeSystemVersion = "Type System Version"; + internal const string UserID = "User ID"; + internal const string UserInstance = "User Instance"; + internal const string WorkstationID = "Workstation ID"; + + #if NETFRAMEWORK + // Odbc + internal const string Driver = "Driver"; + internal const string Dsn = "Dsn"; + internal const string FileDsn = "FileDsn"; + internal const string SaveFile = "SaveFile"; + + // OleDb + internal const string FileName = "File Name"; + internal const string OleDbServices = "OLE DB Services"; + internal const string Provider = "Provider"; + + // OracleClient + internal const string Unicode = "Unicode"; + internal const string OmitOracleConnectionName = "Omit Oracle Connection Name"; + #endif + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringSynonyms.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringSynonyms.cs new file mode 100644 index 0000000000..f7d8881544 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringSynonyms.cs @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Data.Common.ConnectionString +{ + internal static class DbConnectionStringSynonyms + { + //internal const string TransparentNetworkIPResolution = TRANSPARENTNETWORKIPRESOLUTION; + internal const string TRANSPARENTNETWORKIPRESOLUTION = "transparentnetworkipresolution"; + + //internal const string ApplicationName = APP; + internal const string APP = "app"; + + // internal const string IPAddressPreference = IPADDRESSPREFERENCE; + internal const string IPADDRESSPREFERENCE = "ipaddresspreference"; + + //internal const string ApplicationIntent = APPLICATIONINTENT; + internal const string APPLICATIONINTENT = "applicationintent"; + + //internal const string AttachDBFilename = EXTENDEDPROPERTIES + "," + INITIALFILENAME; + internal const string EXTENDEDPROPERTIES = "extended properties"; + internal const string INITIALFILENAME = "initial file name"; + + // internal const string HostNameInCertificate = HOSTNAMEINCERTIFICATE; + internal const string HOSTNAMEINCERTIFICATE = "hostnameincertificate"; + + // internal const string ServerCertificate = SERVERCERTIFICATE; + internal const string SERVERCERTIFICATE = "servercertificate"; + + //internal const string ConnectTimeout = CONNECTIONTIMEOUT + "," +TIMEOUT; + internal const string CONNECTIONTIMEOUT = "connection timeout"; + internal const string TIMEOUT = "timeout"; + + //internal const string ConnectRetryCount = CONNECTRETRYCOUNT; + internal const string CONNECTRETRYCOUNT = "connectretrycount"; + + //internal const string ConnectRetryInterval = CONNECTRETRYINTERVAL; + internal const string CONNECTRETRYINTERVAL = "connectretryinterval"; + + //internal const string CurrentLanguage = LANGUAGE; + internal const string LANGUAGE = "language"; + + //internal const string OraDataSource = SERVER; + //internal const string SqlDataSource = ADDR + "," + ADDRESS + "," + SERVER + "," + NETWORKADDRESS; + internal const string ADDR = "addr"; + internal const string ADDRESS = "address"; + internal const string SERVER = "server"; + internal const string NETWORKADDRESS = "network address"; + + //internal const string InitialCatalog = DATABASE; + internal const string DATABASE = "database"; + + //internal const string IntegratedSecurity = TRUSTEDCONNECTION; + internal const string TRUSTEDCONNECTION = "trusted_connection"; // underscore introduced in everett + + //internal const string LoadBalanceTimeout = ConnectionLifetime; + internal const string ConnectionLifetime = "connection lifetime"; + + //internal const string MultipleActiveResultSets = MULTIPLEACTIVERESULTSETS; + internal const string MULTIPLEACTIVERESULTSETS = "multipleactiveresultsets"; + + //internal const string MultiSubnetFailover = MULTISUBNETFAILOVER; + internal const string MULTISUBNETFAILOVER = "multisubnetfailover"; + + //internal const string NetworkLibrary = NET + "," + NETWORK; + internal const string NET = "net"; + internal const string NETWORK = "network"; + + //internal const string PoolBlockingPeriod = POOLBLOCKINGPERIOD; + internal const string POOLBLOCKINGPERIOD = "poolblockingperiod"; + + //internal const string Password = Pwd; + internal const string Pwd = "pwd"; + + //internal const string PersistSecurityInfo = PERSISTSECURITYINFO; + internal const string PERSISTSECURITYINFO = "persistsecurityinfo"; + + //internal const string TrustServerCertificate = TRUSTSERVERCERTIFICATE; + internal const string TRUSTSERVERCERTIFICATE = "trustservercertificate"; + + //internal const string UserID = UID + "," + User; + internal const string UID = "uid"; + internal const string User = "user"; + + //internal const string WorkstationID = WSID; + internal const string WSID = "wsid"; + + //internal const string server SPNs + internal const string ServerSPN = "ServerSPN"; + internal const string FailoverPartnerSPN = "FailoverPartnerSPN"; + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringUtilities.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringUtilities.cs new file mode 100644 index 0000000000..927b2e62a6 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringUtilities.cs @@ -0,0 +1,592 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using Microsoft.Data.Common.ConnectionString; +using Microsoft.Data.SqlClient; + +namespace Microsoft.Data.Common +{ + internal static class DbConnectionStringUtilities + { + internal static bool ConvertToBoolean(object value) + { + Debug.Assert(value != null, "ConvertToBoolean(null)"); + if (value is string svalue) + { + if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) + { + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no")) + { + return false; + } + else + { + string tmp = svalue.Trim(); // Remove leading & trailing white space. + if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) + { + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) + { + return false; + } + } + return bool.Parse(svalue); + } + try + { + return Convert.ToBoolean(value, CultureInfo.InvariantCulture); + } + catch (InvalidCastException e) + { + throw ADP.ConvertFailed(value.GetType(), typeof(bool), e); + } + } + + internal static bool ConvertToIntegratedSecurity(object value) + { + Debug.Assert(value != null, "ConvertToIntegratedSecurity(null)"); + if (value is string svalue) + { + if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) + return true; + else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no")) + return false; + else + { + string tmp = svalue.Trim(); // Remove leading & trailing white space. + if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) + return true; + else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) + return false; + } + return bool.Parse(svalue); + } + try + { + return Convert.ToBoolean(value, CultureInfo.InvariantCulture); + } + catch (InvalidCastException e) + { + throw ADP.ConvertFailed(value.GetType(), typeof(bool), e); + } + } + + internal static int ConvertToInt32(object value) + { + try + { + return Convert.ToInt32(value, CultureInfo.InvariantCulture); + } + catch (InvalidCastException e) + { + throw ADP.ConvertFailed(value.GetType(), typeof(int), e); + } + } + + internal static string ConvertToString(object value) + { + try + { + return Convert.ToString(value, CultureInfo.InvariantCulture); + } + catch (InvalidCastException e) + { + throw ADP.ConvertFailed(value.GetType(), typeof(string), e); + } + } + + internal static bool TryConvertToApplicationIntent(string value, out ApplicationIntent result) + { + Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); + Debug.Assert(value != null, "TryConvertToApplicationIntent(null,...)"); + + if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(ApplicationIntent.ReadOnly))) + { + result = ApplicationIntent.ReadOnly; + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(ApplicationIntent.ReadWrite))) + { + result = ApplicationIntent.ReadWrite; + return true; + } + else + { + result = DbConnectionStringDefaults.ApplicationIntent; + return false; + } + } + + internal static bool IsValidApplicationIntentValue(ApplicationIntent value) + { + Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); + return value == ApplicationIntent.ReadOnly || value == ApplicationIntent.ReadWrite; + } + + internal static string ApplicationIntentToString(ApplicationIntent value) + { + Debug.Assert(IsValidApplicationIntentValue(value)); + if (value == ApplicationIntent.ReadOnly) + { + return nameof(ApplicationIntent.ReadOnly); + } + else + { + return nameof(ApplicationIntent.ReadWrite); + } + } + + /// + /// This method attempts to convert the given value tp ApplicationIntent enum. The algorithm is: + /// * if the value is from type string, it will be matched against ApplicationIntent enum names only, using ordinal, case-insensitive comparer + /// * if the value is from type ApplicationIntent, it will be used as is + /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum + /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException + /// + /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. + /// + /// application intent value in the valid range + internal static ApplicationIntent ConvertToApplicationIntent(string keyword, object value) + { + Debug.Assert(value != null, "ConvertToApplicationIntent(null)"); + if (value is string sValue) + { + // We could use Enum.TryParse here, but it accepts value combinations like + // "ReadOnly, ReadWrite" which are unwelcome here + // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. + + if (TryConvertToApplicationIntent(sValue, out ApplicationIntent result)) + { + return result; + } + + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToApplicationIntent(sValue, out result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + ApplicationIntent eValue; + + if (value is ApplicationIntent intent) + { + // quick path for the most common case + eValue = intent; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-ApplicationIntent enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (ApplicationIntent)Enum.ToObject(typeof(ApplicationIntent), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), e); + } + } + + // ensure value is in valid range + if (IsValidApplicationIntentValue(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); + } + } + } + + const string SqlPasswordString = "Sql Password"; + [Obsolete("ActiveDirectoryPassword is deprecated.")] + const string ActiveDirectoryPasswordString = "Active Directory Password"; + const string ActiveDirectoryIntegratedString = "Active Directory Integrated"; + const string ActiveDirectoryInteractiveString = "Active Directory Interactive"; + const string ActiveDirectoryServicePrincipalString = "Active Directory Service Principal"; + const string ActiveDirectoryDeviceCodeFlowString = "Active Directory Device Code Flow"; + internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity"; + internal const string ActiveDirectoryMSIString = "Active Directory MSI"; + internal const string ActiveDirectoryDefaultString = "Active Directory Default"; + internal const string ActiveDirectoryWorkloadIdentityString = "Active Directory Workload Identity"; + +#if DEBUG + private static readonly string[] s_supportedAuthenticationModes = + { + "NotSpecified", + "SqlPassword", + "ActiveDirectoryPassword", + "ActiveDirectoryIntegrated", + "ActiveDirectoryInteractive", + "ActiveDirectoryServicePrincipal", + "ActiveDirectoryDeviceCodeFlow", + "ActiveDirectoryManagedIdentity", + "ActiveDirectoryMSI", + "ActiveDirectoryDefault", + "ActiveDirectoryWorkloadIdentity", + }; + + private static bool IsValidAuthenticationMethodEnum() + { + string[] names = Enum.GetNames(typeof(SqlAuthenticationMethod)); + int l = s_supportedAuthenticationModes.Length; + bool listValid; + if (listValid = names.Length == l) + { + for (int i = 0; i < l; i++) + { + if (string.Compare(s_supportedAuthenticationModes[i], names[i], StringComparison.Ordinal) != 0) + { + listValid = false; + } + } + } + return listValid; + } +#endif + + internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result) + { +#if DEBUG + Debug.Assert(IsValidAuthenticationMethodEnum(), "SqlAuthenticationMethod enum has changed, update needed"); +#endif + bool isSuccess = false; + + if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlPasswordString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlPassword, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.SqlPassword; + isSuccess = true; + } + #pragma warning disable 0618 + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryPasswordString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryPassword, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryPassword; + #pragma warning restore 0618 + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryIntegratedString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryIntegrated, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryIntegrated; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryInteractiveString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryInteractive, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryInteractive; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryServicePrincipalString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryServicePrincipal; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDeviceCodeFlowString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryManagedIdentityString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryManagedIdentity; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryMSIString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryMSI, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryMSI; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDefaultString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDefault, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryDefault; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryWorkloadIdentityString) + || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity, CultureInfo.InvariantCulture))) + { + result = SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity; + isSuccess = true; + } + else + { + result = DbConnectionStringDefaults.Authentication; + } + return isSuccess; + } + + /// + /// Convert a string value to the corresponding SqlConnectionColumnEncryptionSetting. + /// + /// + /// + /// + internal static bool TryConvertToColumnEncryptionSetting(string value, out SqlConnectionColumnEncryptionSetting result) + { + bool isSuccess = false; + + if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionColumnEncryptionSetting.Enabled))) + { + result = SqlConnectionColumnEncryptionSetting.Enabled; + isSuccess = true; + } + else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionColumnEncryptionSetting.Disabled))) + { + result = SqlConnectionColumnEncryptionSetting.Disabled; + isSuccess = true; + } + else + { + result = DbConnectionStringDefaults.ColumnEncryptionSetting; + } + + return isSuccess; + } + + /// + /// Is it a valid connection level column encryption setting ? + /// + /// + /// + internal static bool IsValidColumnEncryptionSetting(SqlConnectionColumnEncryptionSetting value) + { + Debug.Assert(Enum.GetNames(typeof(SqlConnectionColumnEncryptionSetting)).Length == 2, "SqlConnectionColumnEncryptionSetting enum has changed, update needed"); + return value == SqlConnectionColumnEncryptionSetting.Enabled || value == SqlConnectionColumnEncryptionSetting.Disabled; + } + + /// + /// Convert connection level column encryption setting value to string. + /// + /// + /// + internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryptionSetting value) + { + Debug.Assert(IsValidColumnEncryptionSetting(value), "value is not a valid connection level column encryption setting."); + + return value switch + { + SqlConnectionColumnEncryptionSetting.Enabled => nameof(SqlConnectionColumnEncryptionSetting.Enabled), + SqlConnectionColumnEncryptionSetting.Disabled => nameof(SqlConnectionColumnEncryptionSetting.Disabled), + _ => null, + }; + } + + internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value) + { + Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 11, "SqlAuthenticationMethod enum has changed, update needed"); + return value == SqlAuthenticationMethod.SqlPassword + #pragma warning disable 0618 + || value == SqlAuthenticationMethod.ActiveDirectoryPassword + #pragma warning restore 0618 + || value == SqlAuthenticationMethod.ActiveDirectoryIntegrated + || value == SqlAuthenticationMethod.ActiveDirectoryInteractive + || value == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal + || value == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow + || value == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity + || value == SqlAuthenticationMethod.ActiveDirectoryMSI + || value == SqlAuthenticationMethod.ActiveDirectoryDefault + || value == SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity + || value == SqlAuthenticationMethod.NotSpecified; + } + + internal static string AuthenticationTypeToString(SqlAuthenticationMethod value) + { + Debug.Assert(IsValidAuthenticationTypeValue(value)); + + return value switch + { + SqlAuthenticationMethod.SqlPassword => SqlPasswordString, + #pragma warning disable 0618 + SqlAuthenticationMethod.ActiveDirectoryPassword => ActiveDirectoryPasswordString, + #pragma warning restore 0618 + SqlAuthenticationMethod.ActiveDirectoryIntegrated => ActiveDirectoryIntegratedString, + SqlAuthenticationMethod.ActiveDirectoryInteractive => ActiveDirectoryInteractiveString, + SqlAuthenticationMethod.ActiveDirectoryServicePrincipal => ActiveDirectoryServicePrincipalString, + SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow => ActiveDirectoryDeviceCodeFlowString, + SqlAuthenticationMethod.ActiveDirectoryManagedIdentity => ActiveDirectoryManagedIdentityString, + SqlAuthenticationMethod.ActiveDirectoryMSI => ActiveDirectoryMSIString, + SqlAuthenticationMethod.ActiveDirectoryDefault => ActiveDirectoryDefaultString, + SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity => ActiveDirectoryWorkloadIdentityString, + _ => null + }; + } + + internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) + { + if (value == null) + { + return DbConnectionStringDefaults.Authentication; + } + + if (value is string sValue) + { + if (TryConvertToAuthenticationType(sValue, out SqlAuthenticationMethod result)) + { + return result; + } + + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToAuthenticationType(sValue, out result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + SqlAuthenticationMethod eValue; + + if (value is SqlAuthenticationMethod method) + { + // quick path for the most common case + eValue = method; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-ApplicationIntent enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (SqlAuthenticationMethod)Enum.ToObject(typeof(SqlAuthenticationMethod), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), e); + } + } + + // ensure value is in valid range + if (IsValidAuthenticationTypeValue(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(SqlAuthenticationMethod), (int)eValue); + } + } + } + + /// + /// Convert the provided value to a SqlConnectionColumnEncryptionSetting. + /// + /// + /// + /// + internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSetting(string keyword, object value) + { + if (value == null) + { + return DbConnectionStringDefaults.ColumnEncryptionSetting; + } + + if (value is string sValue) + { + if (TryConvertToColumnEncryptionSetting(sValue, out SqlConnectionColumnEncryptionSetting result)) + { + return result; + } + + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToColumnEncryptionSetting(sValue, out result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + SqlConnectionColumnEncryptionSetting eValue; + + if (value is SqlConnectionColumnEncryptionSetting setting) + { + // quick path for the most common case + eValue = setting; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["SqlConnectionColumnEncryptionSetting"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-SqlConnectionColumnEncryptionSetting enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (SqlConnectionColumnEncryptionSetting)Enum.ToObject(typeof(SqlConnectionColumnEncryptionSetting), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), e); + } + } + + // ensure value is in valid range + if (IsValidColumnEncryptionSetting(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(SqlConnectionColumnEncryptionSetting), (int)eValue); + } + } + } + } + + + + + + +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/IpAddressPreferenceUtilities.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/IpAddressPreferenceUtilities.cs new file mode 100644 index 0000000000..a9e59dfe2b --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/IpAddressPreferenceUtilities.cs @@ -0,0 +1,115 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.Data.SqlClient; + +namespace Microsoft.Data.Common.ConnectionString +{ + internal static class IpAddressPreferenceUtilities + { + /// + /// IP Address Preference. + /// + private readonly static Dictionary s_preferenceNames = new(StringComparer.InvariantCultureIgnoreCase); + + static IpAddressPreferenceUtilities() + { + foreach (SqlConnectionIPAddressPreference item in Enum.GetValues(typeof(SqlConnectionIPAddressPreference))) + { + s_preferenceNames.Add(item.ToString(), item); + } + } + + /// + /// Convert a string value to the corresponding IPAddressPreference. + /// + /// The string representation of the enumeration name to convert. + /// When this method returns, `result` contains an object of type `SqlConnectionIPAddressPreference` whose value is represented by `value` if the operation succeeds. + /// If the parse operation fails, `result` contains the default value of the `SqlConnectionIPAddressPreference` type. + /// `true` if the value parameter was converted successfully; otherwise, `false`. + internal static bool TryConvertToIPAddressPreference(string value, out SqlConnectionIPAddressPreference result) + { + if (!s_preferenceNames.TryGetValue(value, out result)) + { + result = DbConnectionStringDefaults.IPAddressPreference; + return false; + } + return true; + } + + /// + /// Verifies if the `value` is defined in the expected Enum. + /// + internal static bool IsValidIPAddressPreference(SqlConnectionIPAddressPreference value) + => value == SqlConnectionIPAddressPreference.IPv4First + || value == SqlConnectionIPAddressPreference.IPv6First + || value == SqlConnectionIPAddressPreference.UsePlatformDefault; + + internal static string IPAddressPreferenceToString(SqlConnectionIPAddressPreference value) + => Enum.GetName(typeof(SqlConnectionIPAddressPreference), value); + + internal static SqlConnectionIPAddressPreference ConvertToIPAddressPreference(string keyword, object value) + { + if (value is null) + { + return DbConnectionStringDefaults.IPAddressPreference; // IPv4First + } + + if (value is string sValue) + { + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToIPAddressPreference(sValue, out SqlConnectionIPAddressPreference result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + SqlConnectionIPAddressPreference eValue; + + if (value is SqlConnectionIPAddressPreference preference) + { + eValue = preference; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["SqlConnectionIPAddressPreference"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-SqlConnectionIPAddressPreference enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (SqlConnectionIPAddressPreference)Enum.ToObject(typeof(SqlConnectionIPAddressPreference), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), e); + } + } + + if (IsValidIPAddressPreference(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(SqlConnectionIPAddressPreference), (int)eValue); + } + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/PoolBlockingUtilities.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/PoolBlockingUtilities.cs new file mode 100644 index 0000000000..3a69271317 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/PoolBlockingUtilities.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using Microsoft.Data.SqlClient; + +namespace Microsoft.Data.Common.ConnectionString +{ + internal static class PoolBlockingUtilities + { + internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result) + { + Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); + Debug.Assert(value != null, "TryConvertToPoolBlockingPeriod(null,...)"); + + if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.Auto))) + { + result = PoolBlockingPeriod.Auto; + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.AlwaysBlock))) + { + result = PoolBlockingPeriod.AlwaysBlock; + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.NeverBlock))) + { + result = PoolBlockingPeriod.NeverBlock; + return true; + } + else + { + result = DbConnectionStringDefaults.PoolBlockingPeriod; + return false; + } + } + + internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value) + { + Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); + return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock; + } + + internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value) + { + Debug.Assert(IsValidPoolBlockingPeriodValue(value)); + + return value switch + { + PoolBlockingPeriod.AlwaysBlock => nameof(PoolBlockingPeriod.AlwaysBlock), + PoolBlockingPeriod.NeverBlock => nameof(PoolBlockingPeriod.NeverBlock), + _ => nameof(PoolBlockingPeriod.Auto), + }; + } + + /// + /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is: + /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer + /// * if the value is from type PoolBlockingPeriod, it will be used as is + /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum + /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException + /// + /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. + /// + /// PoolBlockingPeriod value in the valid range + internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) + { + Debug.Assert(value != null, "ConvertToPoolBlockingPeriod(null)"); + if (value is string sValue) + { + // We could use Enum.TryParse here, but it accepts value combinations like + // "ReadOnly, ReadWrite" which are unwelcome here + // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. + + if (TryConvertToPoolBlockingPeriod(sValue, out PoolBlockingPeriod result)) + { + return result; + } + + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToPoolBlockingPeriod(sValue, out result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + PoolBlockingPeriod eValue; + + if (value is PoolBlockingPeriod period) + { + // quick path for the most common case + eValue = period; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-PoolBlockingPeriod enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest + eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e); + } + } + + // ensure value is in valid range + if (IsValidPoolBlockingPeriodValue(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); + } + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs index f72eb5ee59..f9e83b0120 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Text; using System.Text.RegularExpressions; +using Microsoft.Data.Common.ConnectionString; using Microsoft.Data.SqlClient; namespace Microsoft.Data.Common diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs deleted file mode 100644 index 61c189e738..0000000000 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ /dev/null @@ -1,1157 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using Microsoft.Data.SqlClient; - -namespace Microsoft.Data.Common -{ - internal static class DbConnectionStringBuilderUtil - { - internal static bool ConvertToBoolean(object value) - { - Debug.Assert(value != null, "ConvertToBoolean(null)"); - if (value is string svalue) - { - if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) - { - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no")) - { - return false; - } - else - { - string tmp = svalue.Trim(); // Remove leading & trailing white space. - if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) - { - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) - { - return false; - } - } - return bool.Parse(svalue); - } - try - { - return Convert.ToBoolean(value, CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(bool), e); - } - } - - internal static bool ConvertToIntegratedSecurity(object value) - { - Debug.Assert(value != null, "ConvertToIntegratedSecurity(null)"); - if (value is string svalue) - { - if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "true") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "yes")) - return true; - else if (StringComparer.OrdinalIgnoreCase.Equals(svalue, "false") || StringComparer.OrdinalIgnoreCase.Equals(svalue, "no")) - return false; - else - { - string tmp = svalue.Trim(); // Remove leading & trailing white space. - if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "sspi") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "true") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "yes")) - return true; - else if (StringComparer.OrdinalIgnoreCase.Equals(tmp, "false") || StringComparer.OrdinalIgnoreCase.Equals(tmp, "no")) - return false; - } - return bool.Parse(svalue); - } - try - { - return Convert.ToBoolean(value, CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(bool), e); - } - } - - internal static int ConvertToInt32(object value) - { - try - { - return Convert.ToInt32(value, CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(int), e); - } - } - - internal static string ConvertToString(object value) - { - try - { - return Convert.ToString(value, CultureInfo.InvariantCulture); - } - catch (InvalidCastException e) - { - throw ADP.ConvertFailed(value.GetType(), typeof(string), e); - } - } - - #region <> - internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result) - { - Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); - Debug.Assert(value != null, "TryConvertToPoolBlockingPeriod(null,...)"); - - if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.Auto))) - { - result = PoolBlockingPeriod.Auto; - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.AlwaysBlock))) - { - result = PoolBlockingPeriod.AlwaysBlock; - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.NeverBlock))) - { - result = PoolBlockingPeriod.NeverBlock; - return true; - } - else - { - result = DbConnectionStringDefaults.PoolBlockingPeriod; - return false; - } - } - - internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value) - { - Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); - return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock; - } - - internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value) - { - Debug.Assert(IsValidPoolBlockingPeriodValue(value)); - - return value switch - { - PoolBlockingPeriod.AlwaysBlock => nameof(PoolBlockingPeriod.AlwaysBlock), - PoolBlockingPeriod.NeverBlock => nameof(PoolBlockingPeriod.NeverBlock), - _ => nameof(PoolBlockingPeriod.Auto), - }; - } - - /// - /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is: - /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer - /// * if the value is from type PoolBlockingPeriod, it will be used as is - /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum - /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException - /// - /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. - /// - /// PoolBlockingPeriod value in the valid range - internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) - { - Debug.Assert(value != null, "ConvertToPoolBlockingPeriod(null)"); - if (value is string sValue) - { - // We could use Enum.TryParse here, but it accepts value combinations like - // "ReadOnly, ReadWrite" which are unwelcome here - // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - - if (TryConvertToPoolBlockingPeriod(sValue, out PoolBlockingPeriod result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToPoolBlockingPeriod(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - PoolBlockingPeriod eValue; - - if (value is PoolBlockingPeriod period) - { - // quick path for the most common case - eValue = period; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-PoolBlockingPeriod enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e); - } - } - - // ensure value is in valid range - if (IsValidPoolBlockingPeriodValue(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); - } - } - } - #endregion - - internal static bool TryConvertToApplicationIntent(string value, out ApplicationIntent result) - { - Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); - Debug.Assert(value != null, "TryConvertToApplicationIntent(null,...)"); - - if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(ApplicationIntent.ReadOnly))) - { - result = ApplicationIntent.ReadOnly; - return true; - } - else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(ApplicationIntent.ReadWrite))) - { - result = ApplicationIntent.ReadWrite; - return true; - } - else - { - result = DbConnectionStringDefaults.ApplicationIntent; - return false; - } - } - - internal static bool IsValidApplicationIntentValue(ApplicationIntent value) - { - Debug.Assert(Enum.GetNames(typeof(ApplicationIntent)).Length == 2, "ApplicationIntent enum has changed, update needed"); - return value == ApplicationIntent.ReadOnly || value == ApplicationIntent.ReadWrite; - } - - internal static string ApplicationIntentToString(ApplicationIntent value) - { - Debug.Assert(IsValidApplicationIntentValue(value)); - if (value == ApplicationIntent.ReadOnly) - { - return nameof(ApplicationIntent.ReadOnly); - } - else - { - return nameof(ApplicationIntent.ReadWrite); - } - } - - /// - /// This method attempts to convert the given value tp ApplicationIntent enum. The algorithm is: - /// * if the value is from type string, it will be matched against ApplicationIntent enum names only, using ordinal, case-insensitive comparer - /// * if the value is from type ApplicationIntent, it will be used as is - /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum - /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException - /// - /// in any case above, if the converted value is out of valid range, the method raises ArgumentOutOfRangeException. - /// - /// application intent value in the valid range - internal static ApplicationIntent ConvertToApplicationIntent(string keyword, object value) - { - Debug.Assert(value != null, "ConvertToApplicationIntent(null)"); - if (value is string sValue) - { - // We could use Enum.TryParse here, but it accepts value combinations like - // "ReadOnly, ReadWrite" which are unwelcome here - // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. - - if (TryConvertToApplicationIntent(sValue, out ApplicationIntent result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToApplicationIntent(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - ApplicationIntent eValue; - - if (value is ApplicationIntent intent) - { - // quick path for the most common case - eValue = intent; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-ApplicationIntent enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (ApplicationIntent)Enum.ToObject(typeof(ApplicationIntent), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(ApplicationIntent), e); - } - } - - // ensure value is in valid range - if (IsValidApplicationIntentValue(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); - } - } - } - - const string SqlPasswordString = "Sql Password"; - const string ActiveDirectoryPasswordString = "Active Directory Password"; - const string ActiveDirectoryIntegratedString = "Active Directory Integrated"; - const string ActiveDirectoryInteractiveString = "Active Directory Interactive"; - const string ActiveDirectoryServicePrincipalString = "Active Directory Service Principal"; - const string ActiveDirectoryDeviceCodeFlowString = "Active Directory Device Code Flow"; - internal const string ActiveDirectoryManagedIdentityString = "Active Directory Managed Identity"; - internal const string ActiveDirectoryMSIString = "Active Directory MSI"; - internal const string ActiveDirectoryDefaultString = "Active Directory Default"; - internal const string ActiveDirectoryWorkloadIdentityString = "Active Directory Workload Identity"; - -#if DEBUG - private static readonly string[] s_supportedAuthenticationModes = - { - "NotSpecified", - "SqlPassword", - "ActiveDirectoryPassword", - "ActiveDirectoryIntegrated", - "ActiveDirectoryInteractive", - "ActiveDirectoryServicePrincipal", - "ActiveDirectoryDeviceCodeFlow", - "ActiveDirectoryManagedIdentity", - "ActiveDirectoryMSI", - "ActiveDirectoryDefault", - "ActiveDirectoryWorkloadIdentity", - }; - - private static bool IsValidAuthenticationMethodEnum() - { - string[] names = Enum.GetNames(typeof(SqlAuthenticationMethod)); - int l = s_supportedAuthenticationModes.Length; - bool listValid; - if (listValid = names.Length == l) - { - for (int i = 0; i < l; i++) - { - if (string.Compare(s_supportedAuthenticationModes[i], names[i], StringComparison.Ordinal) != 0) - { - listValid = false; - } - } - } - return listValid; - } -#endif - - internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result) - { -#if DEBUG - Debug.Assert(IsValidAuthenticationMethodEnum(), "SqlAuthenticationMethod enum has changed, update needed"); -#endif - bool isSuccess = false; - - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, SqlPasswordString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.SqlPassword, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.SqlPassword; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryPasswordString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryPassword, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryPassword; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryIntegratedString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryIntegrated, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryIntegrated; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryInteractiveString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryInteractive, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryInteractive; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryServicePrincipalString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryServicePrincipal; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDeviceCodeFlowString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryManagedIdentityString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryManagedIdentity; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryMSIString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryMSI, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryMSI; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryDefaultString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryDefault, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryDefault; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, ActiveDirectoryWorkloadIdentityString) - || StringComparer.InvariantCultureIgnoreCase.Equals(value, Convert.ToString(SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity, CultureInfo.InvariantCulture))) - { - result = SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity; - isSuccess = true; - } - else - { - result = DbConnectionStringDefaults.Authentication; - } - return isSuccess; - } - - /// - /// Convert a string value to the corresponding SqlConnectionColumnEncryptionSetting. - /// - /// - /// - /// - internal static bool TryConvertToColumnEncryptionSetting(string value, out SqlConnectionColumnEncryptionSetting result) - { - bool isSuccess = false; - - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionColumnEncryptionSetting.Enabled))) - { - result = SqlConnectionColumnEncryptionSetting.Enabled; - isSuccess = true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionColumnEncryptionSetting.Disabled))) - { - result = SqlConnectionColumnEncryptionSetting.Disabled; - isSuccess = true; - } - else - { - result = DbConnectionStringDefaults.ColumnEncryptionSetting; - } - - return isSuccess; - } - - /// - /// Is it a valid connection level column encryption setting ? - /// - /// - /// - internal static bool IsValidColumnEncryptionSetting(SqlConnectionColumnEncryptionSetting value) - { - Debug.Assert(Enum.GetNames(typeof(SqlConnectionColumnEncryptionSetting)).Length == 2, "SqlConnectionColumnEncryptionSetting enum has changed, update needed"); - return value == SqlConnectionColumnEncryptionSetting.Enabled || value == SqlConnectionColumnEncryptionSetting.Disabled; - } - - /// - /// Convert connection level column encryption setting value to string. - /// - /// - /// - internal static string ColumnEncryptionSettingToString(SqlConnectionColumnEncryptionSetting value) - { - Debug.Assert(IsValidColumnEncryptionSetting(value), "value is not a valid connection level column encryption setting."); - - return value switch - { - SqlConnectionColumnEncryptionSetting.Enabled => nameof(SqlConnectionColumnEncryptionSetting.Enabled), - SqlConnectionColumnEncryptionSetting.Disabled => nameof(SqlConnectionColumnEncryptionSetting.Disabled), - _ => null, - }; - } - - internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value) - { - Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 11, "SqlAuthenticationMethod enum has changed, update needed"); - return value == SqlAuthenticationMethod.SqlPassword - || value == SqlAuthenticationMethod.ActiveDirectoryPassword - || value == SqlAuthenticationMethod.ActiveDirectoryIntegrated - || value == SqlAuthenticationMethod.ActiveDirectoryInteractive - || value == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal - || value == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow - || value == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity - || value == SqlAuthenticationMethod.ActiveDirectoryMSI - || value == SqlAuthenticationMethod.ActiveDirectoryDefault - || value == SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity - || value == SqlAuthenticationMethod.NotSpecified; - } - - internal static string AuthenticationTypeToString(SqlAuthenticationMethod value) - { - Debug.Assert(IsValidAuthenticationTypeValue(value)); - - return value switch - { - SqlAuthenticationMethod.SqlPassword => SqlPasswordString, - SqlAuthenticationMethod.ActiveDirectoryPassword => ActiveDirectoryPasswordString, - SqlAuthenticationMethod.ActiveDirectoryIntegrated => ActiveDirectoryIntegratedString, - SqlAuthenticationMethod.ActiveDirectoryInteractive => ActiveDirectoryInteractiveString, - SqlAuthenticationMethod.ActiveDirectoryServicePrincipal => ActiveDirectoryServicePrincipalString, - SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow => ActiveDirectoryDeviceCodeFlowString, - SqlAuthenticationMethod.ActiveDirectoryManagedIdentity => ActiveDirectoryManagedIdentityString, - SqlAuthenticationMethod.ActiveDirectoryMSI => ActiveDirectoryMSIString, - SqlAuthenticationMethod.ActiveDirectoryDefault => ActiveDirectoryDefaultString, - SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity => ActiveDirectoryWorkloadIdentityString, - _ => null - }; - } - - internal static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) - { - if (value == null) - { - return DbConnectionStringDefaults.Authentication; - } - - if (value is string sValue) - { - if (TryConvertToAuthenticationType(sValue, out SqlAuthenticationMethod result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToAuthenticationType(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlAuthenticationMethod eValue; - - if (value is SqlAuthenticationMethod method) - { - // quick path for the most common case - eValue = method; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["ApplicationIntent"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-ApplicationIntent enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlAuthenticationMethod)Enum.ToObject(typeof(SqlAuthenticationMethod), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlAuthenticationMethod), e); - } - } - - // ensure value is in valid range - if (IsValidAuthenticationTypeValue(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlAuthenticationMethod), (int)eValue); - } - } - } - - /// - /// Convert the provided value to a SqlConnectionColumnEncryptionSetting. - /// - /// - /// - /// - internal static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSetting(string keyword, object value) - { - if (value == null) - { - return DbConnectionStringDefaults.ColumnEncryptionSetting; - } - - if (value is string sValue) - { - if (TryConvertToColumnEncryptionSetting(sValue, out SqlConnectionColumnEncryptionSetting result)) - { - return result; - } - - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToColumnEncryptionSetting(sValue, out result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlConnectionColumnEncryptionSetting eValue; - - if (value is SqlConnectionColumnEncryptionSetting setting) - { - // quick path for the most common case - eValue = setting; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionColumnEncryptionSetting"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionColumnEncryptionSetting enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionColumnEncryptionSetting)Enum.ToObject(typeof(SqlConnectionColumnEncryptionSetting), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionColumnEncryptionSetting), e); - } - } - - // ensure value is in valid range - if (IsValidColumnEncryptionSetting(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionColumnEncryptionSetting), (int)eValue); - } - } - } - - #region <> - /// - /// Convert a string value to the corresponding SqlConnectionAttestationProtocol - /// - /// - /// - /// - internal static bool TryConvertToAttestationProtocol(string value, out SqlConnectionAttestationProtocol result) - { - if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.HGS))) - { - result = SqlConnectionAttestationProtocol.HGS; - return true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.AAS))) - { - result = SqlConnectionAttestationProtocol.AAS; - return true; - } - else if (StringComparer.InvariantCultureIgnoreCase.Equals(value, nameof(SqlConnectionAttestationProtocol.None))) - { - result = SqlConnectionAttestationProtocol.None; - return true; - } - else - { - result = DbConnectionStringDefaults.AttestationProtocol; - return false; - } - } - - internal static bool IsValidAttestationProtocol(SqlConnectionAttestationProtocol value) - { - Debug.Assert(Enum.GetNames(typeof(SqlConnectionAttestationProtocol)).Length == 4, "SqlConnectionAttestationProtocol enum has changed, update needed"); - return value == SqlConnectionAttestationProtocol.NotSpecified - || value == SqlConnectionAttestationProtocol.HGS - || value == SqlConnectionAttestationProtocol.AAS - || value == SqlConnectionAttestationProtocol.None; - } - - internal static string AttestationProtocolToString(SqlConnectionAttestationProtocol value) - { - Debug.Assert(IsValidAttestationProtocol(value), "value is not a valid attestation protocol"); - - return value switch - { - SqlConnectionAttestationProtocol.AAS => nameof(SqlConnectionAttestationProtocol.AAS), - SqlConnectionAttestationProtocol.HGS => nameof(SqlConnectionAttestationProtocol.HGS), - SqlConnectionAttestationProtocol.None => nameof(SqlConnectionAttestationProtocol.None), - _ => null - }; - } - - internal static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(string keyword, object value) - { - if (value == null) - { - return DbConnectionStringDefaults.AttestationProtocol; - } - - if (value is string sValue) - { - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToAttestationProtocol(sValue, out SqlConnectionAttestationProtocol result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlConnectionAttestationProtocol eValue; - - if (value is SqlConnectionAttestationProtocol protocol) - { - eValue = protocol; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionAttestationProtocol"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionAttestationProtocol enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionAttestationProtocol)Enum.ToObject(typeof(SqlConnectionAttestationProtocol), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionAttestationProtocol), e); - } - } - - if (IsValidAttestationProtocol(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionAttestationProtocol), (int)eValue); - } - } - } - - internal static SqlConnectionEncryptOption ConvertToSqlConnectionEncryptOption(string keyword, object value) - { - if (value is null) - { - return DbConnectionStringDefaults.Encrypt; - } - else if(value is SqlConnectionEncryptOption eValue) - { - return eValue; - } - else if (value is string sValue) - { - return SqlConnectionEncryptOption.Parse(sValue); - } - else if(value is bool bValue) - { - return SqlConnectionEncryptOption.Parse(bValue); - } - - throw ADP.InvalidConnectionOptionValue(keyword); - } - - #endregion - - #region <> - /// - /// IP Address Preference. - /// - private readonly static Dictionary s_preferenceNames = new(StringComparer.InvariantCultureIgnoreCase); - - static DbConnectionStringBuilderUtil() - { - foreach (SqlConnectionIPAddressPreference item in Enum.GetValues(typeof(SqlConnectionIPAddressPreference))) - { - s_preferenceNames.Add(item.ToString(), item); - } - } - - /// - /// Convert a string value to the corresponding IPAddressPreference. - /// - /// The string representation of the enumeration name to convert. - /// When this method returns, `result` contains an object of type `SqlConnectionIPAddressPreference` whose value is represented by `value` if the operation succeeds. - /// If the parse operation fails, `result` contains the default value of the `SqlConnectionIPAddressPreference` type. - /// `true` if the value parameter was converted successfully; otherwise, `false`. - internal static bool TryConvertToIPAddressPreference(string value, out SqlConnectionIPAddressPreference result) - { - if (!s_preferenceNames.TryGetValue(value, out result)) - { - result = DbConnectionStringDefaults.IPAddressPreference; - return false; - } - return true; - } - - /// - /// Verifies if the `value` is defined in the expected Enum. - /// - internal static bool IsValidIPAddressPreference(SqlConnectionIPAddressPreference value) - => value == SqlConnectionIPAddressPreference.IPv4First - || value == SqlConnectionIPAddressPreference.IPv6First - || value == SqlConnectionIPAddressPreference.UsePlatformDefault; - - internal static string IPAddressPreferenceToString(SqlConnectionIPAddressPreference value) - => Enum.GetName(typeof(SqlConnectionIPAddressPreference), value); - - internal static SqlConnectionIPAddressPreference ConvertToIPAddressPreference(string keyword, object value) - { - if (value is null) - { - return DbConnectionStringDefaults.IPAddressPreference; // IPv4First - } - - if (value is string sValue) - { - // try again after remove leading & trailing whitespaces. - sValue = sValue.Trim(); - if (TryConvertToIPAddressPreference(sValue, out SqlConnectionIPAddressPreference result)) - { - return result; - } - - // string values must be valid - throw ADP.InvalidConnectionOptionValue(keyword); - } - else - { - // the value is not string, try other options - SqlConnectionIPAddressPreference eValue; - - if (value is SqlConnectionIPAddressPreference preference) - { - eValue = preference; - } - else if (value.GetType().IsEnum) - { - // explicitly block scenarios in which user tries to use wrong enum types, like: - // builder["SqlConnectionIPAddressPreference"] = EnvironmentVariableTarget.Process; - // workaround: explicitly cast non-SqlConnectionIPAddressPreference enums to int - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), null); - } - else - { - try - { - // Enum.ToObject allows only integral and enum values (enums are blocked above), raising ArgumentException for the rest - eValue = (SqlConnectionIPAddressPreference)Enum.ToObject(typeof(SqlConnectionIPAddressPreference), value); - } - catch (ArgumentException e) - { - // to be consistent with the messages we send in case of wrong type usage, replace - // the error with our exception, and keep the original one as inner one for troubleshooting - throw ADP.ConvertFailed(value.GetType(), typeof(SqlConnectionIPAddressPreference), e); - } - } - - if (IsValidIPAddressPreference(eValue)) - { - return eValue; - } - else - { - throw ADP.InvalidEnumerationValue(typeof(SqlConnectionIPAddressPreference), (int)eValue); - } - } - } - #endregion - } - - internal static class DbConnectionStringDefaults - { - internal const ApplicationIntent ApplicationIntent = Microsoft.Data.SqlClient.ApplicationIntent.ReadWrite; - internal const string ApplicationName = -#if NETFRAMEWORK - "Framework Microsoft SqlClient Data Provider"; -#else - "Core Microsoft SqlClient Data Provider"; -#endif - internal const string AttachDBFilename = ""; - internal const int CommandTimeout = 30; - internal const int ConnectTimeout = 15; - internal const bool ContextConnection = false; - -#if NETFRAMEWORK - internal const bool ConnectionReset = true; - internal static readonly bool TransparentNetworkIPResolution = !LocalAppContextSwitches.DisableTNIRByDefault; - internal const string NetworkLibrary = ""; -#endif - internal const string CurrentLanguage = ""; - internal const string DataSource = ""; - internal static readonly SqlConnectionEncryptOption Encrypt = SqlConnectionEncryptOption.Mandatory; - internal const string HostNameInCertificate = ""; - internal const string ServerCertificate = ""; - internal const bool Enlist = true; - internal const string FailoverPartner = ""; - internal const string InitialCatalog = ""; - internal const bool IntegratedSecurity = false; - internal const int LoadBalanceTimeout = 0; // default of 0 means don't use - internal const bool MultipleActiveResultSets = false; - internal const bool MultiSubnetFailover = false; - internal const int MaxPoolSize = 100; - internal const int MinPoolSize = 0; - internal const int PacketSize = 8000; - internal const string Password = ""; - internal const bool PersistSecurityInfo = false; - internal const bool Pooling = true; - internal const bool TrustServerCertificate = false; - internal const string TypeSystemVersion = "Latest"; - internal const string UserID = ""; - internal const bool UserInstance = false; - internal const bool Replication = false; - internal const string WorkstationID = ""; - internal const string TransactionBinding = "Implicit Unbind"; - internal const int ConnectRetryCount = 1; - internal const int ConnectRetryInterval = 10; - internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified; - internal const SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; - internal const string EnclaveAttestationUrl = ""; - internal const SqlConnectionAttestationProtocol AttestationProtocol = SqlConnectionAttestationProtocol.NotSpecified; - internal const SqlConnectionIPAddressPreference IPAddressPreference = SqlConnectionIPAddressPreference.IPv4First; - internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto; - internal const string ServerSPN = ""; - internal const string FailoverPartnerSPN = ""; - } - - internal static class DbConnectionStringKeywords - { -#if NETFRAMEWORK - // Odbc - internal const string Driver = "Driver"; - internal const string Dsn = "Dsn"; - internal const string FileDsn = "FileDsn"; - internal const string SaveFile = "SaveFile"; - - // OleDb - internal const string FileName = "File Name"; - internal const string OleDbServices = "OLE DB Services"; - internal const string Provider = "Provider"; - - // OracleClient - internal const string Unicode = "Unicode"; - internal const string OmitOracleConnectionName = "Omit Oracle Connection Name"; -#endif - // SqlClient - internal const string ApplicationIntent = "Application Intent"; - internal const string ApplicationName = "Application Name"; - internal const string AttachDBFilename = "AttachDbFilename"; - internal const string ConnectTimeout = "Connect Timeout"; - internal const string CommandTimeout = "Command Timeout"; - internal const string ConnectionReset = "Connection Reset"; - internal const string ContextConnection = "Context Connection"; - internal const string CurrentLanguage = "Current Language"; - internal const string Encrypt = "Encrypt"; - internal const string HostNameInCertificate = "Host Name In Certificate"; - internal const string ServerCertificate = "Server Certificate"; - internal const string FailoverPartner = "Failover Partner"; - internal const string InitialCatalog = "Initial Catalog"; - internal const string MultipleActiveResultSets = "Multiple Active Result Sets"; - internal const string MultiSubnetFailover = "Multi Subnet Failover"; - internal const string NetworkLibrary = "Network Library"; - internal const string PacketSize = "Packet Size"; - internal const string Replication = "Replication"; - internal const string TransactionBinding = "Transaction Binding"; - internal const string TrustServerCertificate = "Trust Server Certificate"; - internal const string TypeSystemVersion = "Type System Version"; - internal const string UserInstance = "User Instance"; - internal const string WorkstationID = "Workstation ID"; - internal const string ConnectRetryCount = "Connect Retry Count"; - internal const string ConnectRetryInterval = "Connect Retry Interval"; - internal const string Authentication = "Authentication"; - internal const string ColumnEncryptionSetting = "Column Encryption Setting"; - internal const string EnclaveAttestationUrl = "Enclave Attestation Url"; - internal const string AttestationProtocol = "Attestation Protocol"; - internal const string IPAddressPreference = "IP Address Preference"; - internal const string ServerSPN = "Server SPN"; - internal const string FailoverPartnerSPN = "Failover Partner SPN"; - internal const string TransparentNetworkIPResolution = "Transparent Network IP Resolution"; - - // common keywords (OleDb, OracleClient, SqlClient) - internal const string DataSource = "Data Source"; - internal const string IntegratedSecurity = "Integrated Security"; - internal const string Password = "Password"; - internal const string PersistSecurityInfo = "Persist Security Info"; - internal const string UserID = "User ID"; - - // managed pooling (OracleClient, SqlClient) - internal const string Enlist = "Enlist"; - internal const string LoadBalanceTimeout = "Load Balance Timeout"; - internal const string MaxPoolSize = "Max Pool Size"; - internal const string Pooling = "Pooling"; - internal const string MinPoolSize = "Min Pool Size"; - internal const string PoolBlockingPeriod = "Pool Blocking Period"; - } - - internal static class DbConnectionStringSynonyms - { - //internal const string TransparentNetworkIPResolution = TRANSPARENTNETWORKIPRESOLUTION; - internal const string TRANSPARENTNETWORKIPRESOLUTION = "transparentnetworkipresolution"; - - //internal const string ApplicationName = APP; - internal const string APP = "app"; - - // internal const string IPAddressPreference = IPADDRESSPREFERENCE; - internal const string IPADDRESSPREFERENCE = "ipaddresspreference"; - - //internal const string ApplicationIntent = APPLICATIONINTENT; - internal const string APPLICATIONINTENT = "applicationintent"; - - //internal const string AttachDBFilename = EXTENDEDPROPERTIES+","+INITIALFILENAME; - internal const string EXTENDEDPROPERTIES = "extended properties"; - internal const string INITIALFILENAME = "initial file name"; - - // internal const string HostNameInCertificate = HOSTNAMEINCERTIFICATE; - internal const string HOSTNAMEINCERTIFICATE = "hostnameincertificate"; - - // internal const string ServerCertificate = SERVERCERTIFICATE; - internal const string SERVERCERTIFICATE = "servercertificate"; - - //internal const string ConnectTimeout = CONNECTIONTIMEOUT+","+TIMEOUT; - internal const string CONNECTIONTIMEOUT = "connection timeout"; - internal const string TIMEOUT = "timeout"; - - //internal const string ConnectRetryCount = CONNECTRETRYCOUNT; - internal const string CONNECTRETRYCOUNT = "connectretrycount"; - - //internal const string ConnectRetryInterval = CONNECTRETRYINTERVAL; - internal const string CONNECTRETRYINTERVAL = "connectretryinterval"; - - //internal const string CurrentLanguage = LANGUAGE; - internal const string LANGUAGE = "language"; - - //internal const string OraDataSource = SERVER; - //internal const string SqlDataSource = ADDR+","+ADDRESS+","+SERVER+","+NETWORKADDRESS; - internal const string ADDR = "addr"; - internal const string ADDRESS = "address"; - internal const string SERVER = "server"; - internal const string NETWORKADDRESS = "network address"; - - //internal const string InitialCatalog = DATABASE; - internal const string DATABASE = "database"; - - //internal const string IntegratedSecurity = TRUSTEDCONNECTION; - internal const string TRUSTEDCONNECTION = "trusted_connection"; // underscore introduced in everett - - //internal const string LoadBalanceTimeout = ConnectionLifetime; - internal const string ConnectionLifetime = "connection lifetime"; - - //internal const string MultipleActiveResultSets = MULTIPLEACTIVERESULTSETS; - internal const string MULTIPLEACTIVERESULTSETS = "multipleactiveresultsets"; - - //internal const string MultiSubnetFailover = MULTISUBNETFAILOVER; - internal const string MULTISUBNETFAILOVER = "multisubnetfailover"; - - //internal const string NetworkLibrary = NET+","+NETWORK; - internal const string NET = "net"; - internal const string NETWORK = "network"; - - //internal const string PoolBlockingPeriod = POOLBLOCKINGPERIOD; - internal const string POOLBLOCKINGPERIOD = "poolblockingperiod"; - - //internal const string Password = Pwd; - internal const string Pwd = "pwd"; - - //internal const string PersistSecurityInfo = PERSISTSECURITYINFO; - internal const string PERSISTSECURITYINFO = "persistsecurityinfo"; - - //internal const string TrustServerCertificate = TRUSTSERVERCERTIFICATE; - internal const string TRUSTSERVERCERTIFICATE = "trustservercertificate"; - - //internal const string UserID = UID+","+User; - internal const string UID = "uid"; - internal const string User = "user"; - - //internal const string WorkstationID = WSID; - internal const string WSID = "wsid"; - - //internal const string server SPNs - internal const string ServerSPN = "ServerSPN"; - internal const string FailoverPartnerSPN = "FailoverPartnerSPN"; - } -} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs index a4982981f2..9b9767dae5 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Azure.Core; using Azure.Identity; +using Microsoft.Data.Common.ConnectionString; using Microsoft.Extensions.Caching.Memory; using Microsoft.Identity.Client; using Microsoft.Identity.Client.Extensibility; @@ -549,7 +550,7 @@ private IPublicClientApplication CreateClientAppInstance(PublicClientAppKey publ { publicClientApplication = PublicClientApplicationBuilder.Create(publicClientAppKey._applicationClientId) .WithAuthority(publicClientAppKey._authority) - .WithClientName(Common.DbConnectionStringDefaults.ApplicationName) + .WithClientName(DbConnectionStringDefaults.ApplicationName) .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString()) .WithRedirectUri(publicClientAppKey._redirectUri) .WithParentActivityOrWindow(_iWin32WindowFunc) @@ -560,7 +561,7 @@ private IPublicClientApplication CreateClientAppInstance(PublicClientAppKey publ { publicClientApplication = PublicClientApplicationBuilder.Create(publicClientAppKey._applicationClientId) .WithAuthority(publicClientAppKey._authority) - .WithClientName(Common.DbConnectionStringDefaults.ApplicationName) + .WithClientName(DbConnectionStringDefaults.ApplicationName) .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString()) .WithRedirectUri(publicClientAppKey._redirectUri) .Build(); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs index 58b34fd287..245ea3e45f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs @@ -13,6 +13,7 @@ using System.Security; using System.Security.Permissions; using Microsoft.Data.Common; +using Microsoft.Data.Common.ConnectionString; using Microsoft.Data.SqlClient.LocalDb; namespace Microsoft.Data.SqlClient @@ -23,6 +24,7 @@ internal sealed class SqlConnectionString : DbConnectionOptions // used by pooling classes so it is much easier to verify correctness // when not worried about the class being modified during execution + // @TODO: Remove this in favor of using DbConnectionStringDefaults?? internal static class DEFAULT { internal const ApplicationIntent ApplicationIntent = DbConnectionStringDefaults.ApplicationIntent; @@ -71,6 +73,7 @@ internal static class DEFAULT #endif // NETFRAMEWORK } + // @TODO: Remove in favor of DbConnectionStringKeywords // SqlConnection ConnectionString Options internal static class KEY { @@ -126,6 +129,7 @@ internal static class KEY #endif // NETFRAMEWORK } + // @TODO: Remove in favor DbConnectionStringSynonyms // Constant for the number of duplicate options in the connection string private static class SYNONYM { @@ -575,22 +579,22 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G if (Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity && _hasPasswordKeyword) { - throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString); + throw SQL.NonInteractiveWithPassword(DbConnectionStringUtilities.ActiveDirectoryManagedIdentityString); } if (Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI && _hasPasswordKeyword) { - throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString); + throw SQL.NonInteractiveWithPassword(DbConnectionStringUtilities.ActiveDirectoryMSIString); } if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault && _hasPasswordKeyword) { - throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString); + throw SQL.NonInteractiveWithPassword(DbConnectionStringUtilities.ActiveDirectoryDefaultString); } if (Authentication == SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity && _hasPasswordKeyword) { - throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryWorkloadIdentityString); + throw SQL.NonInteractiveWithPassword(DbConnectionStringUtilities.ActiveDirectoryWorkloadIdentityString); } } @@ -941,7 +945,7 @@ internal ApplicationIntent ConvertValueToApplicationIntent() // wrap Format and Overflow exceptions with Argument one, to be consistent with rest of the keyword types (like int and bool) try { - return DbConnectionStringBuilderUtil.ConvertToApplicationIntent(KEY.ApplicationIntent, value); + return DbConnectionStringUtilities.ConvertToApplicationIntent(KEY.ApplicationIntent, value); } catch (FormatException e) { @@ -973,7 +977,7 @@ internal SqlAuthenticationMethod ConvertValueToAuthenticationType() try { - return DbConnectionStringBuilderUtil.ConvertToAuthenticationType(KEY.Authentication, value); + return DbConnectionStringUtilities.ConvertToAuthenticationType(KEY.Authentication, value); } catch (FormatException e) { @@ -998,7 +1002,7 @@ internal SqlConnectionColumnEncryptionSetting ConvertValueToColumnEncryptionSett try { - return DbConnectionStringBuilderUtil.ConvertToColumnEncryptionSetting(KEY.ColumnEncryptionSetting, value); + return DbConnectionStringUtilities.ConvertToColumnEncryptionSetting(KEY.ColumnEncryptionSetting, value); } catch (FormatException e) { @@ -1023,7 +1027,7 @@ internal SqlConnectionAttestationProtocol ConvertValueToAttestationProtocol() try { - return DbConnectionStringBuilderUtil.ConvertToAttestationProtocol(KEY.AttestationProtocol, value); + return AttestationProtocolUtilities.ConvertToAttestationProtocol(KEY.AttestationProtocol, value); } catch (FormatException e) { @@ -1048,7 +1052,7 @@ internal SqlConnectionIPAddressPreference ConvertValueToIPAddressPreference() try { - return DbConnectionStringBuilderUtil.ConvertToIPAddressPreference(KEY.IPAddressPreference, value); + return IpAddressPreferenceUtilities.ConvertToIPAddressPreference(KEY.IPAddressPreference, value); } catch (FormatException e) { @@ -1069,7 +1073,7 @@ internal PoolBlockingPeriod ConvertValueToPoolBlockingPeriod() try { - return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(KEY.PoolBlockingPeriod, value); + return PoolBlockingUtilities.ConvertToPoolBlockingPeriod(KEY.PoolBlockingPeriod, value); } catch (Exception e) when (e is FormatException || e is OverflowException) { @@ -1086,7 +1090,7 @@ internal SqlConnectionEncryptOption ConvertValueToSqlConnectionEncrypt() try { - return DbConnectionStringBuilderUtil.ConvertToSqlConnectionEncryptOption(KEY.Encrypt, value); + return AttestationProtocolUtilities.ConvertToSqlConnectionEncryptOption(KEY.Encrypt, value); } catch (FormatException e) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs index 4ed5c59198..c86aeccb3c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -15,6 +15,7 @@ using System.Globalization; using System.Reflection; using Microsoft.Data.Common; +using Microsoft.Data.Common.ConnectionString; namespace Microsoft.Data.SqlClient { @@ -274,34 +275,35 @@ private static Dictionary CreateKeywordsDictionary() Debug.Assert((KeywordsCount + SqlConnectionString.SynonymCount) == pairs.Count, "initial expected size is incorrect"); return pairs; } + + // @TODO These methods are completely unnecessary. - private static bool ConvertToBoolean(object value) => DbConnectionStringBuilderUtil.ConvertToBoolean(value); + private static bool ConvertToBoolean(object value) => DbConnectionStringUtilities.ConvertToBoolean(value); - private static int ConvertToInt32(object value) => DbConnectionStringBuilderUtil.ConvertToInt32(value); + private static int ConvertToInt32(object value) => DbConnectionStringUtilities.ConvertToInt32(value); - private static bool ConvertToIntegratedSecurity(object value) => DbConnectionStringBuilderUtil.ConvertToIntegratedSecurity(value); + private static bool ConvertToIntegratedSecurity(object value) => DbConnectionStringUtilities.ConvertToIntegratedSecurity(value); - private static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) => DbConnectionStringBuilderUtil.ConvertToAuthenticationType(keyword, value); + private static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) => DbConnectionStringUtilities.ConvertToAuthenticationType(keyword, value); - private static string ConvertToString(object value) => DbConnectionStringBuilderUtil.ConvertToString(value); + private static string ConvertToString(object value) => DbConnectionStringUtilities.ConvertToString(value); - private static ApplicationIntent ConvertToApplicationIntent(string keyword, object value) => DbConnectionStringBuilderUtil.ConvertToApplicationIntent(keyword, value); + private static ApplicationIntent ConvertToApplicationIntent(string keyword, object value) => DbConnectionStringUtilities.ConvertToApplicationIntent(keyword, value); private static SqlConnectionColumnEncryptionSetting ConvertToColumnEncryptionSetting(string keyword, object value) - => DbConnectionStringBuilderUtil.ConvertToColumnEncryptionSetting(keyword, value); + => DbConnectionStringUtilities.ConvertToColumnEncryptionSetting(keyword, value); private static SqlConnectionAttestationProtocol ConvertToAttestationProtocol(string keyword, object value) - => DbConnectionStringBuilderUtil.ConvertToAttestationProtocol(keyword, value); + => AttestationProtocolUtilities.ConvertToAttestationProtocol(keyword, value); private static SqlConnectionEncryptOption ConvertToSqlConnectionEncryptOption(string keyword, object value) - => DbConnectionStringBuilderUtil.ConvertToSqlConnectionEncryptOption(keyword, value); - + => AttestationProtocolUtilities.ConvertToSqlConnectionEncryptOption(keyword, value); private static SqlConnectionIPAddressPreference ConvertToIPAddressPreference(string keyword, object value) - => DbConnectionStringBuilderUtil.ConvertToIPAddressPreference(keyword, value); + => IpAddressPreferenceUtilities.ConvertToIPAddressPreference(keyword, value); private static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) - => DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(keyword, value); + => PoolBlockingUtilities.ConvertToPoolBlockingPeriod(keyword, value); private object GetAt(Keywords index) { @@ -559,6 +561,8 @@ private void Reset(Keywords index) } } + // @TODO: These methods can be inlined with the property setters. + private void SetValue(string keyword, bool value) => base[keyword] = value.ToString(); private void SetValue(string keyword, int value) => base[keyword] = value.ToString((System.IFormatProvider)null); @@ -571,20 +575,20 @@ private void SetValue(string keyword, string value) private void SetApplicationIntentValue(ApplicationIntent value) { - Debug.Assert(DbConnectionStringBuilderUtil.IsValidApplicationIntentValue(value), "invalid value for ApplicationIntent"); - base[DbConnectionStringKeywords.ApplicationIntent] = DbConnectionStringBuilderUtil.ApplicationIntentToString(value); + Debug.Assert(DbConnectionStringUtilities.IsValidApplicationIntentValue(value), "invalid value for ApplicationIntent"); + base[DbConnectionStringKeywords.ApplicationIntent] = DbConnectionStringUtilities.ApplicationIntentToString(value); } private void SetColumnEncryptionSettingValue(SqlConnectionColumnEncryptionSetting value) { - Debug.Assert(DbConnectionStringBuilderUtil.IsValidColumnEncryptionSetting(value), "Invalid value for SqlConnectionColumnEncryptionSetting"); - base[DbConnectionStringKeywords.ColumnEncryptionSetting] = DbConnectionStringBuilderUtil.ColumnEncryptionSettingToString(value); + Debug.Assert(DbConnectionStringUtilities.IsValidColumnEncryptionSetting(value), "Invalid value for SqlConnectionColumnEncryptionSetting"); + base[DbConnectionStringKeywords.ColumnEncryptionSetting] = DbConnectionStringUtilities.ColumnEncryptionSettingToString(value); } private void SetAttestationProtocolValue(SqlConnectionAttestationProtocol value) { - Debug.Assert(DbConnectionStringBuilderUtil.IsValidAttestationProtocol(value), "Invalid value for SqlConnectionAttestationProtocol"); - base[DbConnectionStringKeywords.AttestationProtocol] = DbConnectionStringBuilderUtil.AttestationProtocolToString(value); + Debug.Assert(AttestationProtocolUtilities.IsValidAttestationProtocol(value), "Invalid value for SqlConnectionAttestationProtocol"); + base[DbConnectionStringKeywords.AttestationProtocol] = AttestationProtocolUtilities.AttestationProtocolToString(value); } private void SetSqlConnectionEncryptionValue(SqlConnectionEncryptOption value) @@ -594,20 +598,20 @@ private void SetSqlConnectionEncryptionValue(SqlConnectionEncryptOption value) private void SetIPAddressPreferenceValue(SqlConnectionIPAddressPreference value) { - Debug.Assert(DbConnectionStringBuilderUtil.IsValidIPAddressPreference(value), "Invalid value for SqlConnectionIPAddressPreference"); - base[DbConnectionStringKeywords.IPAddressPreference] = DbConnectionStringBuilderUtil.IPAddressPreferenceToString(value); + Debug.Assert(IpAddressPreferenceUtilities.IsValidIPAddressPreference(value), "Invalid value for SqlConnectionIPAddressPreference"); + base[DbConnectionStringKeywords.IPAddressPreference] = IpAddressPreferenceUtilities.IPAddressPreferenceToString(value); } private void SetAuthenticationValue(SqlAuthenticationMethod value) { - Debug.Assert(DbConnectionStringBuilderUtil.IsValidAuthenticationTypeValue(value), "Invalid value for AuthenticationType"); - base[DbConnectionStringKeywords.Authentication] = DbConnectionStringBuilderUtil.AuthenticationTypeToString(value); + Debug.Assert(DbConnectionStringUtilities.IsValidAuthenticationTypeValue(value), "Invalid value for AuthenticationType"); + base[DbConnectionStringKeywords.Authentication] = DbConnectionStringUtilities.AuthenticationTypeToString(value); } private void SetPoolBlockingPeriodValue(PoolBlockingPeriod value) { - Debug.Assert(DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value), "Invalid value for PoolBlockingPeriod"); - base[DbConnectionStringKeywords.PoolBlockingPeriod] = DbConnectionStringBuilderUtil.PoolBlockingPeriodToString(value); + Debug.Assert(PoolBlockingUtilities.IsValidPoolBlockingPeriodValue(value), "Invalid value for PoolBlockingPeriod"); + base[DbConnectionStringKeywords.PoolBlockingPeriod] = PoolBlockingUtilities.PoolBlockingPeriodToString(value); } private Exception UnsupportedKeyword(string keyword) @@ -1091,7 +1095,7 @@ public ApplicationIntent ApplicationIntent get => _applicationIntent; set { - if (!DbConnectionStringBuilderUtil.IsValidApplicationIntentValue(value)) + if (!DbConnectionStringUtilities.IsValidApplicationIntentValue(value)) { throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)value); } @@ -1274,7 +1278,7 @@ public SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting get => _columnEncryptionSetting; set { - if (!DbConnectionStringBuilderUtil.IsValidColumnEncryptionSetting(value)) + if (!DbConnectionStringUtilities.IsValidColumnEncryptionSetting(value)) { throw ADP.InvalidEnumerationValue(typeof(SqlConnectionColumnEncryptionSetting), (int)value); } @@ -1309,7 +1313,7 @@ public SqlConnectionAttestationProtocol AttestationProtocol get => _attestationProtocol; set { - if (!DbConnectionStringBuilderUtil.IsValidAttestationProtocol(value)) + if (!AttestationProtocolUtilities.IsValidAttestationProtocol(value)) { throw ADP.InvalidEnumerationValue(typeof(SqlConnectionAttestationProtocol), (int)value); } @@ -1329,7 +1333,7 @@ public SqlConnectionIPAddressPreference IPAddressPreference get => _ipAddressPreference; set { - if (!DbConnectionStringBuilderUtil.IsValidIPAddressPreference(value)) + if (!IpAddressPreferenceUtilities.IsValidIPAddressPreference(value)) { throw ADP.InvalidEnumerationValue(typeof(SqlConnectionIPAddressPreference), (int)value); } @@ -1443,7 +1447,7 @@ public SqlAuthenticationMethod Authentication get => _authentication; set { - if (!DbConnectionStringBuilderUtil.IsValidAuthenticationTypeValue(value)) + if (!DbConnectionStringUtilities.IsValidAuthenticationTypeValue(value)) { throw ADP.InvalidEnumerationValue(typeof(SqlAuthenticationMethod), (int)value); } @@ -1640,7 +1644,7 @@ public PoolBlockingPeriod PoolBlockingPeriod get => _poolBlockingPeriod; set { - if (!DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value)) + if (!PoolBlockingUtilities.IsValidPoolBlockingPeriodValue(value)) { throw ADP.InvalidEnumerationValue(typeof(PoolBlockingPeriod), (int)value); } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs index c398110849..835f1ae640 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -492,7 +492,7 @@ static internal Exception UserInstanceFailoverNotCompatible() } static internal Exception CredentialsNotProvided(SqlAuthenticationMethod auth) { - return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_CredentialsNotProvided, DbConnectionStringBuilderUtil.AuthenticationTypeToString(auth))); + return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_CredentialsNotProvided, DbConnectionStringUtilities.AuthenticationTypeToString(auth))); } static internal Exception InvalidCertAuth() { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs index 18f60d0724..280469a5e0 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -4,6 +4,7 @@ using System; using System.Data; +using Microsoft.Data.Common.ConnectionString; namespace Microsoft.Data.SqlClient { @@ -14,7 +15,7 @@ internal static class TdsEnums // internal tdsparser constants - public const string SQL_PROVIDER_NAME = Common.DbConnectionStringDefaults.ApplicationName; + public const string SQL_PROVIDER_NAME = DbConnectionStringDefaults.ApplicationName; public static readonly decimal SQL_SMALL_MONEY_MIN = new(-214748.3648); public static readonly decimal SQL_SMALL_MONEY_MAX = new(214748.3647);